Structuri de Date

Descărcați ca doc, pdf sau txt
Descărcați ca doc, pdf sau txt
Sunteți pe pagina 1din 203

Curs2

1.TIPURI DE DATE
1.1. DATE I INFORMAII
n practic se face deosebire ntre o dat i o informaie. Exemplele oferite n cele mai
multe cazuri sunt edificatoare. Exist i tendine de a oferi definiii pentru date i pentru
informaii. Dilemele cnd o informaie este considerat dat i cnd o dat este o informaie,
sunt rezolvate pentru muli specialiti, dar rmn dileme pentru o alt categorie de specialiti.
Din punct de vedere al programatorului, ceea ce face obiectul prelucrrii sunt de fapt iruri
de bii care reprezint date sau informaii, funcie de contextul n care sunt generate i de modul
n care se interpreteaz rezultatele. Pentru a nu complica i mai mult problematica, se consider
c n activitatea de programare se opereaz cu date. Toate intrrile i ieirile programelor sunt
date. Sistemele de prelucrare, ns sunt intitulate n continuare sisteme informaionale sau
sisteme informatice, n mod ornamental din punctul de vedere al programatorilor.
n realitate, atunci cnd acestea funcioneaz corect, prelucreaz ntr-adevr informaii.
Atunci cnd, ns, fluxurile sunt greoaie i determin un nivel de istorism costisitor, prelucrrile
sunt ale unor date certe.
Pentru ca n literatura de specialitate capitolul deinut descrierii operanzilor informaii
sau date se numete STRUCTURI DE DATE, n continuare, nu se mai face deosebirea dintre
informaie i dat. Utilizatorii sunt aceia care decide dac ofer spre prelucrare informaii sau
date i dac rezultatele prelucrrii sunt date sau sunt informaii.
1.2 CLASIFICRI ALE DATELOR
Exist numeroase puncte de vedere de a aborda gruparea datelor, fiecare constituindu-
se ntr-un criteriu. Ceea ce este ns adevrat, este legat de faptul c fiecrei date i se ataaz
totalitatea atributelor ce rezult din multitudinea de clasificri ce se iau n considerare.
a) Criteriul variabilitii grupeaz datele n:
- date constante, care nu se modific ntr-un interval de timp sau pe durata execuiei
programului; n cazul n care pentru a face un program lizibil constantele sunt puse n
coresponde cu anumii identificatori, n programe sunt vehiculai acetia din urm,
formnd constantele simbolice.
- date variabile, ale cror niveluri se modific fie ntr-un interval de timp, fie pe
parcursul execuiei unui program; ntotdeauna se vorbete de o valoare iniial, valori
intermediare i o valoare final; numrul valorilor intermediare determin mecanismele
necesare prelucrrilor, includerea n structuri repetitive sau stocarea lor n fiiere;
b) Criteriul compunerii difereniaz datele astfel:
- date simple sau elementare, fiecare avnd o anumit semnificaie i fiind independente de
celelalte date care apar ntr-un context specificat; datele elementare se mai numesc atomi;
- date compuse sau structurate, formate din date elementare sau date la rndul lor structurate;
fiecare component are o anumit poziie n cadrul structurii i mpreun cu celelalte formeaz
un ntreg; ntre prile care alctuiesc o dat compus exist legturi n primul rnd de coninut
i numai toate la un loc caracterizeaz un fenomen, un proces sau un individ dintr-o
colectivitate: apartenena i poziia fiecrei componente se precizeaz explicit la descrierea datei
structurate;
c) Criteriul semnificaiei coninutului conduce la:
- date care fac obiectul operaiilor de prelucrare, adic particip ca operanzi n expresii, se
iniializeaz prin atribuiri sau operaii de intrare, se stocheaz pe supori, se afieaz sau se
transmit ca parametri;
- date care permit adresarea operanzilor i care au valori cuprinse ntre limite precizate, care prin
calcule de adrese localizeaz corect fie operanzi, fie alte date de adresare, fie funcii de
prelucrare;
- date ce efectueaz prelucrarea, care apar ca succesiuni de instruciuni direct executabile dac
fiierul care le aparine este ncrcat n memoria unui calculator i se comand lansarea n
execuie a acestuia;
d) Criteriul naturii datelor genereaz tipurile de date urmtoare:
- date de tip ntreg, ale cror elemente aparin mulimii Z;
- date de tip real, ale cror elemente aparin mulimii R;
- date de tip complex, ale cror elemente aparin mulimii C, iar coeficienii care desemneaz
partea real i partea imaginar aparin mulimii R;
- date de tip boolean, ale cror elemente aparin mulimii
{TRUE, FALSE} sau mulimii {0, 1};
- date de tip caracter, ale cror elemente aparin mulimii caracterelor ce sunt definite prin
combinaie de bii la nivelul unui bait; din cele 256 de combinaii unele sunt grupate pentru
litere, altele pentru cifre, altele pentru caractere speciale i pentru caractere de control;
corespunztor, sunt definite date de tip alfabetic, de tip numeric, date de tip caractere de control
etc.; aceste date au cte un singur element din mulimea ce-i definete tipul;
- date de tip ir de caractere reprezint o compunere prin concatenare a datelor de tip caracter;
datele acestea au un delimitator al sfritului de ir, fie o constant de tip ntreg la nceput,
preciznd numrul de caractere care intr n alctuirea irului;
e) Criteriul construirii tipurilor conduce la:
- date de tip fundamental ce aparin unui tip implementat n fiecare limbaj de programare,
precum tipurile ntreg, real, caracter, boolean, complex; programatorul are posibilitatea definirii
constantelor simbolice i variabilelor proprii specificnd tipurile fundamentale i alege
prelucrrile compatibile acestora;
- date de tip derivat care se obin prin includerea n cadrul unor structuri a componentelor avnd
unul din tipurile fundamentale implementate n limbaj; rezultatul obinut este un tip de dat
derivat care se pune n coresponden cu un identificator i care este folosit de programator
pentru a defini variabilele n program avnd respectivul tip;
f) Criteriul dispunerii n memoria intern, grupeaz datele n:
- date dispuse n zone contigue care permit localizarea uneia dintre ele cunoscnd o adres i o
deplasare; n cazul n care zonele de memorie ocupate au aceeai lungime, adresa fiecrei date
se constituie ca termen al unei progresii aritmetice i este calculat cunoscnd adresa primei date
i poziia n irul datelor contigue a elementului cutat;
- date dispersate n memoria intern - se obin n cazul alocrii dinamice a memoriei necesare,
ceea ce impune stocarea i conservarea adresei zonei de memorie asociat fiecrei date; dac
datele dispuse n zone contigue, au realizat proiectarea alocrii n faza de compilare, datelor
dispersate li se aloc memorie efectiv n faza de execuie i nu exist posibilitatea ca n mod
direct s se construiasc modele de calcul a adreselor fizice pe care datele le ocup, mai ales
dac alocarea memoriei este un proces ce depinde de testarea unor condiii din program;
g) Criteriul cmpului de aciune, mparte datele n:
- date cu caracter global care se definesc o singur dat, dar care sunt utilizate din orice punct al
programului sau a funciilor i procedurilor care intr n componena lui; aceste date se definesc
i li se aloc memorie o singur dat i au cmpul de aciune cel mai cuprinztor;
- date cu caracter local sunt n fiecare procedur i li se aloc memorie dinamic, automat, la
apelarea fiecrei proceduri sau funcii; odat cu revenirea n secvena apelat deci la ieirea din
funcie sau din procedura, are loc eliberarea memoriei alocate (dealocarea memoriei);
variabilele locale nu sunt folosite dect n procedura sau funcia unde au fost definite;
- date de tip registru au rolul de a pune la dispoziie programatorului n limbaje evoluate,
accesul la registrele calculatorului; n cazul unei folosiri judicioase exist posibilitatea creterii
vitezei de prelucrare, iar n cazul folosirii abuzive a registrelor se obine fenomenul invers;
h) Criteriul definirii domeniului presupune:
- date al cror domeniu este specificat prin limita inferioar, limita superioar i forma de
prezentare generic a elementelor;
- date al cror domeniu este definit odat cu enumerare elementelor care i formeaz.
i) Criteriul alocrii memoriei, grupeaz datele n:
- date statistice calcule de alocare a memoriei se efectueaz n faza de compilare, iar nainte de
execuie, alocarea este efectiv;
- date dinamice a cror memorie este alocat i dealocat n timpul execuiei programului, prin
funcii de bibliotec apelate.
ntr-un program, o anumit dat este astfel definit nct se ncadreaz ntr-una din subgrupele
fiecrui criteriu. Astfel, definirea:
// PROGRAM definire:
#include<.>
#include<.>
................................
int k;
main( )
{

}
dintr-un program C/C++ se interpreteaz astfel:
- k este o dat variabil (criteriul variabilitii);
- k este o dat elementar (criteriul compunerii);
- k este o dat de tip operand (criteriul semnificaiei);
- k este o dat de tip ntreg (criteriul naturii datelor);
- k este o dat de tip fundamental (criteriul construirii tipurilor);
- k este o dat dispus ntr-o zon contigua (criteriul dispunerii n memoria intern);
- k este o dat global (criteriul cmpului de aciune).
Deci, k este un operand, variabila elementar, global, de tipul fundamental ntreg, dispus
ntr-o zon contigu.
1.3. MODELE DE PREZENTARE A DATELOR
ntre forma de reprezentare natural sau extern a datelor i forma de reprezentare intern a
acestora, exist mari diferene.
Reprezentarea intern a datelor, se realizeaz utiliznd algoritmi de codificare, care pun n
coresponden datele cu iruri de bii. Pentru fiecare tip de dat se definete lungimea zonei de
memorie i algoritmul de codificare, precum i codurile operaiilor care utilizeaz operanzii n
concordan cu caracteristicile de tip ale acestora.
a) Modelul de verificare a concordanei tip-coninut-adresa
Modele de reprezentare a datelor au n componena lor: LSUPi, LIMFi valori ce
precizeaz limita inferioar i limita superioar a intervalului creia i aparine data de tip i
specificat;
Ai indicatorul algoritmului de realizare a reprezentrii interne pentru datele de tip i;
f() funcia de apartenen a datei la un anumit tip;
M - mulimea funciilor de conversie;
n - numrul de tipuri de date;
k - cerine de aliniere a adresei de nceput a zonei de memorie
k {1,2,4,8}
Ti - natura i a datei;
adr ( ) funcia de determinare a adresei unei zone de memorie pus n coresponden cu
un identificator specificat
adr: J -> N
unde:
J este mulimea identificatorilor;
N submulime a numerelor naturale cu care se localizeaz fiecare bait al zonei de
memorie la dispoziia programatorului;


N b a N ] , [
~
unde a,b N, a <b i delimiteaz posibiliti hardware de
dispunere n memorie a programului;
cont ( ) funcia coninut a zonei de memorie
cont:
i
n
i
i
D U T J
1


tip ( ) - funcia de identificare a tipului variabilei
tip : J -> T
Mulimea Tj a naturii datelor fundamentale implementate n limbajul de programare Lj , se
definete prin:
Tj = { T1, T2, ...,Tn }
Dac j este C,
TC = {int, bool, float, char, string}
deci n=5, fr a fi luate n considerare variantele pentru datele ntregi, reale i posibilitatea
de a specifica seturi de valori.
Pentru datele de natur boolean, LSUP2 este 1 sau TRUE i LINF2 este 0 sau FALSE.
Pentru datele de natur real A3, corespunde modului de construire a mantisei i
caracteristicii precum i dispunerea acestora pe cei 6 baii.
Pentru datele ntregi H, mulimea funciilor de conversie are elementele:
H = {f11, f12, f13, f14, f15}
00 00 00 00 00 00 14 11
c
a
b
bbb
- cifra --
- a sau b --
[ ] - construcie opional
Constantele ntregi li se CC
+
---
ddd
Dintre acestea numai f11 i f14 sunt inversabile, deci tabloul funciilor:
fij ( ) i = 1,2,3,4,5
j =1,2,3,4,5
demonstreaz c se efectueaz conversii n toate direciile cu o anumit pierdere a unor
simboluri din descrierea iniial.
Cerinele de aliniere sunt specifice particularitii hardware a sistemelor de calcul. n
cazul n care la compilare nu este realizat optimizarea alocrii memoriei, apar zone
neutilizabile cu efecte ce sunt interpretate mai dificil.
Declararea:
. . . . . . . . . . . . . . . .
char a;
float b;
char c;
char d;
n absena optimizrii alocrii de memorie, conduce la rezervarea:

n cazul optimizrii, secvenei de program i corespunde
Este posibil optimizarea datorit comunicativitii dispunerii operanzilor ntr-o secven, atunci
cnd acetia sunt elementari i nu apare problema redefinirii.
Funcia de apartenena a datelor la un anumit tip se definete:
f: U x Di-> { FALSE, TRUE}
unde:
U reprezint mulimea irurilor ce se genereaz cu simbolurile alfabetului construit pentru un
limbaj.
Di intervalul sau mulimea elementelor specifice tipului de date i

'

Di x daca TRUE
Di x daca FALSE
i x f ) , (
De exemplu:
f(13, int) =TRUE, pentru c 13 [-32768, 32767] Z
Dint fiind domeniul ntregilor, n timp ce
f( -4, bool) = FALSE, pentru ca 4 nu aparine mulimii {FALSE, TRUE}.
n secvena:
. . . . . . . . . . . . . . . . .
int x;
. . . . . . . . . . . . . . . . .
x = 20;
. . . . . . . . . . . . . . . . .
presupunnd c n compilare i editare de legturi, variabilei x i se asociaz zona de memorie:
a b c d
A : 8
A+8 A+16 A+20
b d a c

A : 8

A+8
07AA0
00 00 00 00 00 00 14 11
x
c
a
b
bbb
- cifra --
- a sau b --
[ ] - construcie opional
Constantele ntregi li se CC
+
---
aaa
ccc
hhh
jjj
iii
ggg
fff
eee
ddd
bbb
ddd
111 777 10 11 ni1 nn
adr(x) = 07AA0
cont(x) = (00000014)16
f(cont(x), int) = TRUE
tip (x) = int
Deci:
f(cont(x), tip(x)) = TRUE
Funcia de aliniere:
K: adresa x tipi -> TRUE

'

i
i
i
k adresa daca FALSE
k adresa daca TRUE
) T K(adresa,
M
unde ki este factorul de aliniere cerut prin construcie pentru tipul de date Ti .
K(07AA0, int) = TRUE
pentru c 07AA0

4
K(adr(x), tip (x)) = TRUE
Se spune c variabila x este:
- corect alocat
- corect iniializat
dac i numai dac
f (cont(x), tip(x)) AND K(adr(x),tip(x)) = TRUE
b) Modelul de generare a constantelor pentru un tip specificat de date
Folosind convenii i simboluri, se definesc reguli (mecanisme) de generare a
constantelor.
Astfel, se noteaz:
Constantelor ntregi li se asociaz modelul de generare:
Putem verifica dac irurile:
0
- 125
. 3
+- 60
44
sunt sau nu constante ntregi. Cu uurin ne dm seama c irurile . 3 +-60 i 44- nu ndeplinesc
cerinele impuse de ablonul model.
Pentru constantele de tip real se prezint modelul de generare:
] [ ] ... [ [.] ] ... [ cc e c cc c cc
E
1
]
1

'

+
1
]
1

'

1
]
1

'

+
irurile:
+1 . 2e-4
- . 3 E2
2 . e-1
1e + 4
sunt constante reale ntruct respect regulile de generare incluse n ablon
c) Modele de descriere a datelor folosind grafuri
c
a
b
bbb
- cifra --
- a sau b --
[ ] - construcie opional
Constantele ntregi li se CC
+
---
ccccc. . . c
aaa
ccc
hhh
jjj
iii
ggg
fff
eee
ddd
bbb
ddd
111 777 10 11 ni1 nn
ntruct grafurile permit punerea n eviden a
interdependenelor dintre elemente omogene sau neomogene, se
consider utilizarea lor ca fiind sugestiv n cazul structurilor
de date.
Prin convenie, se stabilesc c nodurile care prezint numai
arce incidente spre interior corespund datelor elementare, iar
nodurile care au arce incidente spre interior i spre exterior
corespund datelor de grup.
Astfel, graful:
este interpretat ca: data compus a are n alctuirea ei datele elementare b,c i d.
Graful:
0 - ->0 - ->0- ->0
a b c d
corespunde datelor interdependente, n care b urmeaz lui a, c urmeaz lui b i d urmeaz
lui c. Nodurile a,b,c,d sunt fie date elementare, fie date compuse, iar pentru stabilirea relaiei de
precedenta este necesar memorarea unor adrese.
Pentru realizarea n cadrul programelor a definirii structurilor complexe de date este
necesar reprezentarea acestora folosind grafuri i dup aceea scrierea n program a unei forme
liniarizate neambigue.
De exemplu, pentru structura de tip arborescent, se utilizeaz scrierea parantetica, ce
presupune ca elementele de pe acelai nivel s fie separate prin virgul, iar pentru trecerea la
nivel inferior, utilizarea unei paranteze rotunde deschise.
Revenirea la nivelul precedent se marcheaz cu o parantez nchis. Astfel grafului:
i corespunde liniarizarea:
a(b(d,e,f,g), c(h(i,j)))
d) Modele care permit implementarea recursivitii n descrierea datelor
Se face deosebire ntre modelele recursive de descriere a datelor precum:
<semn> : : = + -
<cifra> : : = 0 1 2 3 4 5 6 7 8 9
<ntreg fr semn> : : = <cifra> <ntreg fr semn><cifra>
<cifra><ntreg fr semn>
<ntreg> : : = <ntreg fr semn> <semn><ntreg fr semn>
i modelele care implementeaz, recursivitatea n descrierea datelor.
Astfel, construcia:
b
c
a
aaa
ccc
hhh
jjj
iii
ggg
fff
eee
ddd
bbb
111 777 10 11 ni1 nn
tip_de_data = (
_ntreg,_)
pune n eviden ca dat
conine dou date elementare i
anume care are tipul ntreg i
care are tipul .
Aceste modele permit descrierea
structurilor de date autoreferite
liste, stive i arbori.
e) Modele grafice
Sunt utilizate
reprezentri grafice pentru
locaiile de memorie asociate
variabilelor i constantelor unui
program. Prin arce se stabilesc legturile dintre locaii. Acest model de descriere a datelor este
sugestiv i fr ambiguitate.
Construcia:
reprezint o list, fiecare component avnd dou elemente: primul reprezint informaia util
avnd valorile 1,7 i 10, iar al doilea conine adrese. Arcele orientate indic locaia a crei
adresa este memorat n componenta precedent.
f) Modelul vectorial
Se consider un vector avnd un numr dat de componente. Fiecare component are o
semnificaie precizat, iar componentele luate n ansamblu lor descriu complet i corect
structurile de date.
Se observ c pentru datele elementare, multe dintre componentele vectorului sunt
nule. Zerourile, arat lipsa dependenelor n aval i n amonte sau mrimea distanei dintre dou
componente.
Funcia distant se definete astfel:
d(x,y) = adr (y) adr (x)
Definim lg (x,Ti), funcia lungime a zonei de memorie asociat operandului x.
De exemplu, pentru secvena de program:
. . . . . . . . . . . . . . .
x : extended;
y : comp;
z : shortint;
w : word;
. . . . . . . . . . . . . . .
lg(x, extended) = 10
lg (y, comp) = 8
lg (z, shortint) = 1
lg(w, word) = 4
lg : IxT -> {1,2,4,6,8,10}
Programul care pune n eviden lungimile tipurilor de date ale limbajului C/C++ este:
//program dimensiune_tip;
#include <iostream.h>
#include <malloc.h>
main()
{
cout<<"\n - - - - - - - - - - - - - - - - - - - - - - - - ";
cout<<"\n Reprezentarea datelor de tip ntreg";
cout<<"\n - - - - - - - - - - - - - - - - - - - - - - - - ";
cout<<"\n char: "<< sizeof(char)<<" octet";
cout<<"\n unsigned char: "<< sizeof(unsigned char)<<" octet";
cout<<"\n int: "<< sizeof(int)<<" octet";
cout<<"\n unsigned int: "<< sizeof(unsigned int)<<" octet";
cout<<"\n signed int: "<< sizeof(signed int)<<" octeti";
cout<<"\n short int: "<<sizeof(short int)<<" octeti";
cout<<"\n long int: "<< sizeof(long int)<<" octeti";
cout<<"\n - - - - - - - - - - - - - - - - - - - - - - - - ";
cout<<"\n Reprezentarea datelor de tip real";
cout<<"\n - - - - - - - - - - - - - - - - - - - - - - - - ";
cout<<"\n float: "<< sizeof(float)<<" octeti";
cout<<"\n double: "<<sizeof(double)<<" octeti";
cout<<"\n long double: "<<sizeof(long double)<<" octeti";
cout<<"\n - - - - - - - - - - - - - - - - - - - - - - - - ";
cout<<"\n Reprezentarea datelor de tip caracter";
cout<<"\n - - - - - - - - - - - - - - - - - - - - - - - - ";
cout<<"\n char: "<<sizeof(char)<<" octet";
cout<<"\n - - - - - - - - - - - - - - - - - - - - - - - - ";
cout<<"\n Reprezentarea datelor de tip logic";
cout<<"\n - - - - - - - - - - - - - - - - - - - - - - - - ";
cout<<"\n boolean: "<< sizeof(bool)<<" octet";
}Dac variabilele x i y sunt contigue
d(x,y) = lg (x,Ti)
n cazul vectorilor i matricilor, apare posibilitatea punerii n eviden a contiguitii. Pentru un
vector x cu n componente:
d(x[j], x [j+1]) = 1g (x[1],Ti ), oricare j aparine mulimii {1,2,. . .n}
n cazul n care variabilele ocup zone de memorie necontigue:
d(x,y) > lg (x,Ti )
inegalitatea depinznd de modalitatea n care s-a fcut alocarea memoriei.
Redefinirile sau reacoperirile, corespund unor distante fie nule, fie mai mici dect
lungimea cmpului considerat reper.
d(x,y) < lg (x) = l1
lg (y) = 12
adr(x) < adr(y) < adr(x) + 11
Uniunile de date apar drept cazuri particulare n acest model de descriere a datelor.
union a: T1 , b:T2 ,c :T3;
dist(a,b) = dist(a,c) = dist(b,c) = 0
Lungimea zonei de memorie ocupat de variabilele union este: 1= max
{lg(a,T1),lg(b,T2),lg (c,T3))
g) Modelul obiectelor generice
Datele aparinnd unui anumit tip apar n expresii precedate sau urmate de anumii
operatori. De asemenea, ele sunt parametrii pentru anumite funcii.
Modelul include:
- forma generica de construire a datei de un tip specificat
- operatorii i funciile care utilizeaz datele definite pentru tipul respectiv, precum i excepiile
de utilizare.
Acest model permite descrierea corect a secvenelor de program, cu construirea de obiecte
acolo unde limbajele de programare implementeaz cerinele programrii orientate pe obiect.
Exist multe alte modaliti de descriere riguroas a datelor, toate ns se subordoneaz
unor obiecte dintre care cel mai important este crearea premiselor analizei semantice, pentru
y
12
x
l1
punerea n eviden mai nti a corectitudinii descrierilor de date i mai apoi a corectitudinii
programelor.
Curs3
2. DATE ELEMENTARE
2.1. Cerine de definire
n toate programele scrise apar variabile simple. Acestea definesc fie variabile de control, fie
variabile n care se regsesc totaluri sau rezultate independente de alte evaluri ale programului.
Fiecare data pe care un programator o specific are caracteristici proprii, ce determin tipul i
locul n care este definit, modul de alocare a memoriei, modalitatea de iniializare i felul n
care este folosit n final coninutul su.
Vom considera spre exemplificare un program P n care se utilizeaz variabilele i de tip
ntreg i s de tip real.
Variabila i este o variabil de control folosit n regsirea elementelor vectorului definit prin:
float x[100];
Variabila s este definit astfel:
float s;
Pentru variabilele independente, definirea n secven este comutativ fr a influena
rezultatul prelucrrii.
Sevenele:

'

'

i; int
s; float
: variabile
S2.
s; float
i; int
: variabile
S1.
sunt echivalente, rezultatele prelucrrii unui program ce conine una din cele dou secvene sunt
identice.
Dac programului P i se ataeaz o secven S la stnga, se obine programul P1.
P1 = S || P
unde || este operatorul de concatenare
Dac programului P i se ataeaz o secven S la dreapta, se obine programul P2.
P2 = P || S.
Se spune ca secvena S de instruciuni este comutativa n raport cu operatorul ||
dac:
rez (S || P;d) = rez (P || S;d)
unde rez ( ) este funcia rezultat definit:
rez: P X C -> C
unde P mulimea programelor
C mulimea constantelor elementare, vectoriale,
matricile i de alte structuri.
n cazul secvenelor S1, S2 dac
rez(S1 || P;d) = rez(S2 || P;d)
se spune c cele dou secvene sunt echivalente, adic
(S1 U S2) || P
Observ c n programul P, variabila de control i trebuie iniializat cu valoarea 1 i atinge cel
mult valoarea 100.
Domeniul.
Dom (i) = [1,100] N.
Definirea cu tipul integer determin:
Dom(int) = [-37768, 32767] N
deci Dom (i) Dm (int) unde Dom este funcia domeniu
Dom : J -> D
Aceast funcie permite tratarea tipurilor fundamentale int, float, bool ca identificatori cu
caracteristici prefixate prin construcia limbajului C/C++.
Dac presupunem c cele 100 de componente ale vectorului x au valori cuprinse ntre 1
i 200 suma lor nu depete 200 * 100 = 20000. Deci:
Dom (s) = [100,20000] N
Dom (float) = [2.9E 39,1.7E38]
Dom (s) Dom (float)
Faptul c domeniile variabilelor i i s, sunt incluse n domeniile definite tipurilor, determin
excluderea situaiei obinerii de rezultate trunchiate i deci de pierdere a controlului coninutului
lor.
Oportunitatea alegerii tipului ntreg sau real, este pus n eviden de ponderea
funciilor de conversie care se activeaz la execuie.
Pentru un programator care a lucrat ntr-un limbaj de asamblare, secvenele:
int i; int i;
float s; float s;
. . . . . . . . . . . . . . . . . . . . . . . . . .
i = 1.; i = 1;
s = 0; s = 0.;
sunt diferite pentru c:
- n prima secven se genereaz constanta 1. ca avnd tip float.
Deci ocup o zon de memorie de 6 bytes (constante de maxim 7-8 cifre). Zona este structurat
pentru caracteristica i mantisa. Constanta 0 se genereaz ntr-o zon de memorie de 2 bytes
corespunztoare tipului int.
- n modul obiect generat la compilare, i = 1 i s = 0, se concretizeaz prin copieri (mutri) ale
coninutului zonelor de memorie ce corespund operanzilor din dreapta semnului egal, n alte
zone de memorie ce corespund operanzilor din stnga semnului egal.
- instruciunile de copiere (mutare) presupun operanzi omogeni; dac operandul receptor este de
tip ntreg, atunci operandul emitor trebuie s fie tot de tip ntreg; dac operandul receptor este
de tip real, atunci i operandul emitor trebuie s fie de tip real. n caz de neomogenitate,
compilatorul genereaz secvene de apelare a funciilor de conversie.
- secvena S1 necesit 2 apeluri de funcii de conversie i anume: conversie de la real la ntreg, f13
i conversie de la real la ntreg f31.
rez1 = f13(1.)
copiere rez1 -> i
rez2 = f31 (0)
copiere rez2 -> s
- ntruct n secvena S2, exist concordana ntre tipurile constantelor generate ca operanzi
emitori i operanzi receptori, nu mai sunt necesare apelri ale funciilor de conversie.
Ca o cerin n alegerea tipului, este realizarea unui nivel ct mai redus al apelurilor funciilor de
conversie.
Posibilitatea definirii la utilizare a variabilelor elementare, conduce uneori la realizarea unei
ocupri a memoriei cu operanzi cu grad redus de folosire.
Exist limbaje, ca de exemplu Fortran i Basic, care nu necesit definirea explicit a
variabilelor, ci acestea se definesc la prima utilizare, tipul fiind precizat odat cu respectarea
unei reguli de construire a identificatorilor.
Gradul de utilizare este marcat prin numrul de instruciuni n care variabilele apar, sau
prin frecvena de modificare a coninutului lor. Un program devine cu att mai bun cu ct
mprtierea variabilelor elementare este mai redus.
Astfel, dac n secvena S1 apare variabila i, iar n secvena S2 apare variabila j i
programul
P = S1 || S2.
observm c domeniile celor dou variabile care au acelai tip sunt disjuncte, deci este definit o
singur variabil ce este utilizat de ambele secvene.
Dac:
rez (S2; rez (S1; i), j) = rez (S2; rez(S1;i) ,i)
secvena:
var
int i;
int j:
. . . . . . . . . . . . .
S1 (i):
. . . . . . . . . . . . .
S2 (j):
va fi modificat obinndu-se secvena:
var
int i;
. . . . . . . . . . . . .
S1 (i):
. . . . . . . . . . . . .
S2 (i):
Caracterul local sau global, dinamic sau static, este dat de contextul n care se utilizeaz fiecare
variabil. Important este ca programul s realizeze pentru un exemplu de test din specificaiile
de programare, acelai coninut pentru toate punctele de control.
Dac pentru exemplul de control descrie prin variabilele 1, 2, 3, 4, 5 ale vectorului x de
5 componente, la iteraia a treia, n specificaiile de programare se indic pentru variabila s
valoarea 6 i dac prin:
rez (S1 S1 S1; s,i)
cont (s) este 6, nseamn c definirea s este corect. Dac ns n locul ascociat structurii
repetitive, este definit s i este iniializat,
rez (S1 S1 S1;s, i) conduce la cont (s) cu valoarea 3, pentru c celelalte valori se pierd
la fiecare activare a blocului, se conchide c definirea local determin erori asupra rezultatului.
2.2. Cerine de iniializare i utilizare
Variabilele elementare se iniializeaz sub control de ctre programator. Ele au semnificaii
precum:
- definesc dimensiunile problemei de rezolvat;
- definesc precizia rezultatelor;
- definesc opiuni ale utilizatorului ce determin funcii care se activeaz:
- conin rezultate cu grad de cuprindere difereniat;
- controleaz execuia repetitiv a secvenelor;
- specific limite de valori pe care le iau unele variabile;
- conin nivele puse n coresponden cu tipuri de erori, tipuri de rezultate sau evenimente n
prelucrare.
Compilatoarele moderne, pun n eviden situaiile n care se definesc i se utilizeaz variabile
elementare, fr ca n prealabil s fie iniializate. Iniializarea unei variabile elementare se
efectueaz:
- la definire exist limbaje care permit definirea i iniializarea variabilei (de exemplu, n limbajul
C, construciile int s = 0, i = 0; sunt frecvente);
- printr-o funcie de citire;
- prin atribuire, variabila elementar aflndu-se n membrul stng;
O variabil elementar se definete pentru a i se utiliza coninutul cel puin o singur dat ntr-o
expresie, ca parametru ntr-o funcie sau ntr-o expresie indicial.
Afiarea rezultatului coninut de o variabil elementar apare ca o utilizare a acesteia
sub forma de parametru n funcia writeln ( );
Se spune c variabila elementar i este corect definit i corect utilizat dac:
cont_spcf (i,n) = = cont_prg (i,m)
unde, cont_spcf ( ) este funcia de coninut a variabilei i dup efectuarea pasului n al
algoritmului precizat n specificaiile de programare, iar cont_prg ( ) este funcia de coninut a
variabilei i dup executarea instruciunii a m a din program instruciune care delimiteaz
sfritul pasului n al algoritului descris n specificaii.
Dac:
cont_prg (i,m) = = cont_prg(i,m+1)
oricare este m [1, M] N unde, M arat numrul de instruciuni executabile care formeaz
programul, se spune c i nu i modific coninutul, este deci o constant i ori este defectuos
utilizat, ori trebuia definit nu ca variabil ci ca o constant simbolic.
Urma programului se obine prin:
cout<< (m, cont_prg (i, m));
m = 1, 2, . . . .M
sau numai pentru valori modificate:
if (cont_prg (i,m) != cont_prg (i, m+1))
cout<<(M+1,cont_prg (i,m+1));
n cazul n care datele elementare se definesc numai pentru seturi de valori dintr-o
mulime, se utilizeaz funcia de apartenen, ce pune n eviden corectitudinea reiniializrii
unei variabile sau a rezultatelor din calcule.
Dac:
f (cont_prg (x,m), Ti ) = =FALSE
nseamn c la instruciunea a m a a programului, valoarea variabilei elementare x nu
corespunde setului de valori T ataat acesteia.
De exemplu, dac pentru marcarea erorilor de execuie se atribuie codurile:
0 dac execuia s-a desfurat normal;
1 dac exist tentativa mpririi prin zero;
2 dac matricea este singular;
3 dac valorile unei expresii indiciale depesc limitele pentru care este definit operandul de
tip masiv,
Ti = {0,1,2,3}
Dac ntr-o funcie de inversare a matricei, variabila ierr este definit pe mulimea Ti i
dac ntr-un punct k al funciei i se atribuie valoarea 7,
f (cont_prg (ierr,k),Ti ) = = FALSE
nseamn ca s-a nregsitrat o eroare, o ndeprtare de specificaiile de programare. Este posibil
ca uneori specificaiile de programare s suporte modificri, care reflect cerine de finee
realizate n program. Mulimea tipurilor de erori este diversificat i atunci se obine:
T

i = Ti U {4,5,6,7}
unde codurile 4,5,6,7, corespund unor noi situaii ce conduc la ntreruperea execuiei.
n acest caz:
f(cont_prg(ierr,k), T

i ) = = TRUE
Cerinele de iniializare pentru date de acelai tip, conduc la trecerea de la variabile
elementare, la variabile de tip masiv.
Construciei:
int a, b, c, d, e, f;
. . . . . . . . . . . . . . . . . . . . . . . .
a = 0;
b = 0;
c = 0;
d = 0;
e = 0;
f = 0;
. . . . . . . . . . . . . . . . . . . . . . . .
i corespunde secvena compact:
var
int x[6];
int i;
. . . . . . . . . . . . . . . . . . . . . . . .
for (i =0; i<6; i++) x [i] = 0;
sau secvena:
int x[6] = {0,0,0,0,0,0};
Alegerea dintre date elementare i date compuse, este legat n primul rnd de modul
de calcul a adreselor i de obiectivul urmrit prin prelucrare iar n al doilea rnd, de
compactitatea programului.
Datele elementare, se constituie ca o mulime de noduri ale unui graf n care mulimea
arcelor este vid. Adresele variabilelor elementare au caracter aleator. n general, nu se
stabilete o relaie de calcul a adreselor unor elemente din mulimea de date elementare, avnd
ca reper un element aparinnd de asemenea acestei mulimi.
2.3. Cerine de lizibilitate a programului
Datele elementare sunt puse n coresponden cu identificatori sugestivi. Astfel, pentru
calculul volumului unei prisme paralelipipedice se definesc:
. . . . . . . . . . . . . . . . . . . . . . . .
int lungime, lime, nlime, volum;
{
cin>>lungime>>nime>>lime;
volum=lungime*lime*nlime;
cout<<volum = << volum;
. . . . . . . . . . . . . . . . . . . . . . . .
n cazul definirii unei variabile compuse omogene, secvena echivalent este:
. . . . . . . . . . . . . . . . . . . . . . . .
int x[4];
{
cin<<x[1]<< x[2]<<x[3];
x[4] = x [1] *x [2] *x[3];
cout<< volum = <<x[4];
. . . . . . . . . . . . . . . . . . . . . . . .
Lizibilitatea programului n acest caz, este crescut numai ca posibilitate de urmrire a
sintaxei acestuia. n prima form se nelege exact semnificaia prelucrrii. n plus, dac se
accept utilizarea variabilelor de stare globale, care sunt n totalitate variabile elementare, dup
apelarea funciilor, se fac teste i se continu prelucrarea numai dac acestea au nivelul pus n
coresponden cu execuia cerut.
Aceasta este de fapt cauza necesitii standardizrii rspunsului pe care l ofer
funciile n domeniul valorilor de stare pe care le returneaz.
Secvena:
. . . . . . . . . . . . . . . . . . . . . . . .
int stare;
. . . . . . . . . . . . . . . . . . . . . . . .
stare = f1(p1. . . . .pn );
if (stare != 0) then
return(1);
stare=f2 (p1 . . . . .pn );
if (stare != 0) then
return(2);
. . . . . . . . . . . . . . . . . . . . . . . .
ilustreaz controlul permanent al programatorului asupra rezultatelor prelucrrii folosind
variabila elementar stare.
Curs4
3. MASIVELE STRUCTURI DE DATE OMOGENE I CONTIGUE
3.1. Masive unidimensionale (vectori)
Sunt puine programele n care nu apar definite masive unidimensionale. Problemele de
ordonare a irurilor, de calcul a indicatorilor statistici medie i dispersie, programele pentru
gsirea elementului minim i multe altele presupun stocarea valorilor numerice ale irurilor n
zona de memorie care n mod folcloric le numim vectori. Ceea ce de fapt se recunoate sub
numele de vector este n realitate o structur de date omogene.
Prin definirea:
int x[10];
se specific:
x este o dat compus din 10 elemente;
elementul este de tip ntreg;
primul element al structurii este x [0]
al doilea element este x [1]
. . . . . . . . . . . . . . . . . . . . . . . .
al zecelea element al structurii este x [9].
int). ; (x[i] lg lg(x..)
n
1 i


Dac funcia:
lg(a;b)
se definete pentru tipurile standard prin
lg (x;b) = lg(.;b) = k
unde, k e lungimea standard alocat la compilare pentru o dat de tipul b i
lg(x0 , x1 , x2 . . . .xn ;b) = lg (x0;b) + lg (x1 ;b) + . . . +lg(xn;b) =lg(.;b) + lg (.;b) +. . .+lg (.;b) = kb
+ kb + . . . kb = n
*
kb
rezult c:
lg(x,int) = 10
*
2 bytes
Modul grafic de reprezentare a alocrii memoriei pentru elementele vectorului x, conduce la:
x[0]
x[1] X[2] x[8]
x[9]
xxx
X
999
X
222
X
111
X
000
Pentru c elementele sunt de acelai tip:
lg(x[0], . ) = lg(x[1], . ) = . . . = lg(x[9], .)
Dac notm:
= adr(x[i])
= adr (x[i+1])
- = lg (x[i],.)
Se observ c :
dist (x[i], x[i+1]) = lg(x[i], int) = 2
ntruct elementele ocup o zon de memorie contigu.
Se definesc funciile:
succ() care desemneaz succesorul unui element ntr-un ir;
pred() care desemneaz preecesorul unui element ntr-un ir astfel:
succ(x[i]) = x [i+1]
pred(x[i]) = x [i-1]
Aceste funcii au prioritile:
succ(pred(x[i])) = succ(x[i-1]) = x[i]
pred(succ(x[i])) = pred(x[i+1]) = x[i]
Deci, funciile succ() i pred() sunt una invers celeilalte.
Pentru extremitile vectorului
pred(x[0]) =
succ(x[9]) =
succ ( ) = pred ( ) =
Direct, se observ c:
succ
0
(x[i]) = x [i]
pred
0
(x[i]) = x [i]
succ
m
(x[i]) = x[i+m]
pred
n
(x [i]) = x[i-n]

succ
m
(pred
n
(x[i])) = x[i-n+m]
pred
n
(succ
m
(x[i])) = x[i+m n]
Dac elementul x[i] este considerat reper (baza), adresele celorlalte elemente se calculeaz
folosind deplasarea fa de elementul reper.
Funcia deplasare:
depl(a;b)
va permite calculul deplasrii lui a fa de b.
Astfel.
depl(x[i+k],x[i]) = (i+k i)*lg (.,int)=k*lg (.,int)
depl (x[i],x [i+k] = -k*lg(.,int)
sau depl(x[i+k],x[i] = adr(x[i+k]) adr(x[i]).
Dac x reprezint structura de date omogene n totalitatea ei, iar x[0], x[1], . . . . ,x[9] sunt
prile care o compun, din reprezentarea grafic rezult c:
adr(x) = adr(x[1]).
Se definete: adr(a+b) = adr(a) + (b 1)*lg( .,int),
unde:
a este numele datei structurate;
b poziia elementului a crui adres se dorete a fi calculat;
adr(a+b) = adr(b+a)
Din calcule de adrese rezult c:
adr(x[n]) adr(x[1])
. . . . . . . . . . . . . . . . . . + 1 = n
lg(x[1])
Contiguitatea este pus n eviden prin definirea funciei de distan DST(a,b), care indic
numrul de bytes neaparintori ai datelor a i b care separ data a de data b.
DST (a,b) = 5
a
b
xxx
X
999
X
222
X
111
X
000
TRUE, dac adr(a) T [A
i
, A
f
]]]
FALSE, n caz
contrar c
fp(a) = ff
TRUE, dac a T [B
i
, B
f
]]]
gm(a)
===
n raport cu modul de definire a funciei DST ( ), observm c
DST(x[i] .x[i+1]) = 0 i {0,2,. . . . . 9}
DST(x[i] .x[i]) = 0
DST(a,a) = 0
DST (a,b) > = 0
DST (a,b) <= DST(a,c) + DST (c,b)
11 <= 11 + 12 + lg (b) + 12
lg(b) + 2*12 >= 0
DST (a,b) = DST (b,a)
Reprezentat ca structur arborescent, vectorul are modelul grafic:
n programe, se specific numrul maxim al componentelor vectorului, avndu-se grija ca n
problemele ce se rezolv, numrul efectiv s nu depeasc dimensiunea declarat.
De exemplu, n secvena:
. . . . . . . . . . . . . . . . .
int x[10];
int n;
. . . . . . . . . . . . . . . . .
cin<<n;
for( i= 0; i<n ;i++)
x[i] = 0;
identificm urmtoarele inexactiti:
pentru faptul c n nu rezult a fi iniializat cu o valoare cuprins ntre 0 i 9, exist posibilitatea
ca n cazul n=15, adresa calculat s fie
adr(x+15) = adr(x) + (15-1)*lg(x,int)
i s cuprind unui cuvnt ce urmeaz cu mult mai departe de componenta x[9], cuvnt al crui
coninut devine zero.
Prin parametrii compilrii, se controleaz expresiile indiciale, aa fel nct s fie
incluse n intervalul definit pentru variaie, specificat n calificatorul tip[e1. .e2], evitndu-se
distrugerea necontrolat a operanzilor adiaceni masivului unidimensional.
Exemplul dat arat c expresia indicial, aparine intervalului [0,9] N, ns limbajul
C/C++ permite definirea unor limite ntr-o form mult mai flexibil.
De exemplu, definirea:
int y[11];
permite referirea elementelor:
,y [-7], y[-6], . . . . y[0], y[1], y[2], y[3]
adr(y) = adr(y[-7])
DST(y[ -7], y[-6]) = [-6-(7)-1]*lg(. . int) = 0
i acest vector rezult c este contiguu.
Numrul de componente este dat de:
a
11
b
12
c
xxx
X
999
X
222
X
111
X
000
TRUE, dac adr(a) T [A
i
, A
f
]]]
FALSE, n caz
contrar c
fp(a) = ff
TRUE, dac a T [B
i
, B
f
]]]
FALSE, n caz
contrar c
gm(a)
===
11 1
) int lg(..
]) 7 [ ( ]) 3 [ (
+

eger
y adr y adr

adr(y+4) = adr(y[-7] ) +[4-(-7) ]*lg(y, int) = = adr(y[-7] ) + 11*lg(y, int)
succ(y[ -5]) = = y [-4]
pred(y[-1]) = = y[-2]
depl(y[-7+2], y[-7]) = = 2*lg(y, int)
Deplasarea lui y[-6] fa de elementul y[2]:
depl(y[-6], y[2]) = = depl(y[2-8], y[2]) = (2-8-2)*lg(y, int) = = -8*lg(y, int)
depl(y[2], y[-6]) = = [2-(-6)]*lg (y, int) = = 8*lg(y, int)
Se observ c:
depl(a,b) = = - depl (b,a)
sau
depl (a, b) + depl(b,a) = = 0
Proprietile masivelor unidimensionale, conduc la ideea stocrii ntr-o zon de memorie a
adresei unuia dintre termeni i prin adugarea sau scderea unei raii egale cu lungimea unui
element, se procedeaz la baleierea spre dreapta sau spre stnga a celorlalte elemente.
: = adr(x[1])
: = + i*lg(x[1], int)
conduce la situaia n care
cont ( ) adr (x[i+1])
Datorit contiguitii memoriei i a regulilor de regsire a elementelor, masivul unidimensional
nu conine n mod distinct informaii privind poziia elementelor sale. Cunoscnd numele
masivului, referirea elementelor se realizeaz specificnd acest nume i poziia elementului
cuprins ntre paranteze drepte sub forma unei expresii indiciale.
Expresia indicial are un tip oarecare, ns nainte de efectuarea calculului de adresa
are loc conversia spre ntreg, care este atribuit funciei int( ). Deci funcia int ( ), *realizeaz
rotunjirea n minus a valorii expresiei indiciale.
Astfel, pentru definirea:
int z[100]; unde indicele pleac de la 6,
adresa elementului
z [ e
a
+ cos (b) /
c
]
se calculeaz astfel :
adr (z [ e
a
+ cos (b) /
c
] ) = adr ( z[6] ) + ( int (e
a
+ cos (b) /
c
)) *
* lg ( z[6] , int)
Funciile de validare a adreselor se vor defini astfel :
unde:
x[i] x[i+1]
x [1]
. . .
1 - adr
i +1 _adr
TRUE, dac adr(a) T [A
i
, A
f
]]]
FALSE, n caz
contrar c
fp(a) = ff
TRUE, dac a T [B
i
, B
f
]]]
FALSE, n caz
contrar c
gm(a)
===
aaa
a[0] aa a[1] aa
a[0][0] aa a[0][1] aa a[0][2] aa a[0][3] aa a[1][1] aa a[1][2] aa a[1][0] aa a[1][3] aa
aaa
Col 0 CC
a
00 00
Col 01 CC Col 02 CC Col 03 CC
a
10 11
a
01 00
a
11 11
a
02 00
a
13 11
a
03 00
a
12 11
fp( ) este funcia de validare adrese n raport cu programul ;
bm( ) este funcia de validare a adreselor n raport cu un masiv m;
Ai este adresa se nceput a programului ;
Af este adresa se sfrit a programului ;
Bi este a dresa de nceput a masivului m ;
Bf este adresa de sfrit a masivului m.
Dac programul P este format din instruciunile I1, I2, , I100 atunci :
adr ( I1 ) = Ai
adr ( I100 ) = Af.
Dac n programul P este definit masivul : int x[10];
atunci :
adr ( x[0] ) = Bi
adr (x[99] ) = Bf.
Vom spune c este corect folosit expresia indicial e
a
+ cos (b) /
c
dac :
g( x [ e
a
+ cos (b) /
c
] ) = TRUE
sau dac :
int (e
a
+ cos (b) /
c
) * ( lg ( z[6] , int ) < Bf - Bi
Dac se ia n considerare c:
f( x [ e
a
+ cos (b) /
c
] ) = TRUE
pot apare situaii n care s fie modificate alte zone dect cele asociate masivului
unidimensional.
Dac se iau n considerare reprezentri simplificate, pentru localizarea unui element x[i] al unui
masiv unidimensional, se folosete formula cunoscut :
x[0] + x[i 0] * lungime_element
Atunci cnd se construiesc programe n care se definesc masive unidimensionale, alegerea
tipului, alegerea limitei inferioare i a limitei superioare pentru variaie, depind de contextul
problemei dar i de formulele identificate prin inducie matematic pentru explorare, folosind
structuri repetitive.
De fiecare dat, trebuie avut grij ca numrul de componente ce rezult la definire s fie
acoperitor pentru problemele ce se rezolv.
Pentru stabilirea numrului maxim de componente ale vectorilor ce sunt definii, se consider:
L lungimea n baii a disponibilului de memorie;
Lp lungimea n baii a necesarului de memorie pentru program (instruciuni executabile i alte
definiri);
M numrul de masive unidimensionale de tip Ti, avnd acelai numr de componente care
apar n program;
x numrul maxim de componente ale unui masiv.
x = int( ( L Lp ) / ( N * lg( . ;Ti ) ) ).

n cazul n care cele N masive au dimensiuni variabile d1, d2, , dN, condiia de utilizare corecta
a resursei memoriei este ca :
d1 + d2 + +dN

int( ( L Lp ) / lg( . ;Ti ) ) .


3.2 Masive bidimensionale (matrice)
Este aproape sigur c n activitatea de programare, matriceale ocup ca importan un loc
deosebit. i tot att este de adevrat c lucrul corect cu matrice ofer rezultate rapide, cum la fel
de adevrat este c utilizarea defectuoas reduce considerabil ansa de a obine rezultate corecte.
Singura modalitate de a realiza programe corecte utiliznd matrice, este cunoaterea
mecanismelor de implementare a acestora n diferite limbaje de programare, precum i studierea
proprietilor ce decurg din ele.
Pornind de la ideea c o matrice este format din linii, iar liniile sunt formate din elemente, se
ajunge la modelul grafic al matricei, care apare sub forma unei arborescene organizat pe trei
nivele.
Pentru definirea :
aaa
a[1] aa a[1][0] aa a[1][1] aa a[1][n] aa
a[2] aa
a[2][0] aa
a[2][1] aa a[2][n] aa
a[m] aa a[m][0] aa a[m][1] aa a[m][n] aa
aaa
a[0] aa a[1] aa
a[0][0] aa a[0][1] aa a[0][2] aa a[0][3] aa a[1][1] aa a[1][2] aa a[1][0] aa a[1][3] aa
aaa
Col 0 CC
a
00 00
Col 01 CC Col 02 CC Col 03 CC
a
10 11
a
01 00
a
11 11
a
02 00
a
13 11
a
03 00
a
12 11
int a[2][4];
rezult c matricea a este format din 2 linii; fiecare linie avnd cte 4 componente.
Modelul grafic pentru matricea a este :
Modelul grafic presupune existena a trei nivele:
la nivelul cel mai nalt se afl ntregul, matricea a;
la nivelul imediat urmtor se afl primele pri n care se descompun matricea i anume: liniile
acesteia a[0] i a[1];
la nivelul al treilea se afl elementele grupate pentru fiecare linie n parte.
O alt definiie a matricei conduce la descompunerea n coloane i a coloanelor n elemente.
Deci n ambele cazuri se obin structuri arborescente, elementele de la baza arborescenelor
reprezentnd dispunerea contigu a liniilor una n continuarea celeilalte, respectiv, a coloanelor
una n continuarea celeilalte, respectiv, a coloanelor una n continuarea celeilalte, regsind
ambele situaii ca modaliti de liniarizare a matricelor.
Dac se consider o matrice A, avnd m linii i n coloane, elementele fiind de tipul Ti, adresa
elementului a[i][j] se calculeaz fie dup formula :
adr( a[i][j] ) = adr( a[0][0] ) + ( ( i 0 ) * n + j ) * lg( a , Ti ) ,
dac liniarizarea se face linie cu linie, fie dup formula :
adr( a[i][j] ) = adr( a[0][0] ) + ( ( j 0 ) * m + i ) * lg( a , Ti ) ,
dac liniarizarea se face coloan dup coloan.
Intuitiv, o matrice poate fi privit lund n considerare numai primul nivel de descompunere, ca
vector de linii sau ca vector de coloane.
Fiecare linie sau coloan, prin descompunerea la nivelul urmtor, este privit ca vector de
elemente. Deci, n final o matrice poate fi privit ca vector de vectori.
Definirea :
int a[2][4];
pune n eviden exact acest lucru.
Din aceast descriere rezult c :
adr( a ) = adr( a[0] ) = adr( a[0][0] )
adr( a[i] ) = adr( a[i][0] )
Dac dispunerea elementelor este linie cu linie,
DST( a[i][n] , a[i+1][0] ) = 0.
Dac dispunerea elementelor este coloan dup coloan,
DST( a[m][j] , a[0][j+1] ) = 0
Deplasarea elementelor aij fa de elementul akh , se calculeaz dup relaia :
depl (a[i][j] . a[k][h]) = adr(a[k][h]) adr(a[i][j]) =
= adr (a[0][0]) + ((k-0)n + h) * *lg(a, Ti ) (adr(a[0][i])+
+ ((i-0)n + j) *lg(a, Ti ) =
aaa
a[1] aa a[1][0] aa a[1][1] aa a[1][n] aa
a[2] aa
a[2][0] aa
a[2][1] aa a[2][n] aa
a[m] aa a[m][0] aa a[m][1] aa a[m][n] aa
aaa
a[0] aa a[1] aa
a[0][0] aa a[0][1] aa a[0][2] aa a[0][3] aa a[1][1] aa a[1][2] aa a[1][0] aa a[1][3] aa
aaa
Col 0 CC
a
00 00
Col 01 CC Col 02 CC Col 03 CC
a
10 11
a
01 00
a
11 11
a
02 00
a
13 11
a
03 00
a
12 11
= lg(a, Ti )*[(k-0)n (i-0)n + h j] =
= lg(a, Ti)*[(k-i)n + h j]
Numrul de elemente al matricei n se obine
n * m 1
) T lg(a,
]) adr(a[0][0 ]) adr(a[m][n
i
+

n cazul dispunerii linie de linie,


succ(a[i][n]) = a[i+1][0]
pred(a[i][0]) = a [i-1][n]
succ (a[i]) = a[i+1][0]
pred (a[i]) = a[i-1][0]
succ(a[i+k]) = succ (a[i])
pred (a[i]) = pred (a[i+k])
n mod asemntor,
adr(a+i) = adr(a[0]) + (i-0)*lg(a[0])
adr (a[i] +j) = adr(a[i]) + (j-0)* lg (a[0][0])
lg(a[i]) = lg(a[i][0]) + . . .+lg(a[i][n])
sau
lg(a[i]) = n*lg(a[i][0])
deci:
adr(a+i) = adr(a[0]) + (i-0)*n*lg(a[i][0])
Dac privim matricele ca vectori de vectori, n mod corespunztor se identific forma grafic:
unde a, a[i], a[i][j] se definesc n aa fel nct s reflecte urmtorul coninut:
a[i] = adr(a[i][1])
i = 0,2, . . . .m
a = adr (a[0]) .
Definirea unei matrice ca avnd m linii i n coloane, deci n totalul m*n elemente i explorarea
elementelor prin includerea unui alt numr de linii i coloane conduce la o localizare a
elementelor nsoit de un rezultat eronat, a crui provenien e necesar a fi interpretat i
reconstituit.
Se consider matricea:
2 4 1 1 7
20 19 18 17 16
15 14 13 12 11
10 9 8 7 6
5 4 3 2 1
stocat n:
int a[5][5];
definit i iniializat n programul principal, iar ntr-o procedur se consider c avem
definirea:
a[0] a[0][0] a[0][1] a[0][n]
aaa
a[1] aa a[1][0] aa a[1][1] aa a[1][n] aa
a[2] aa
a[2][0] aa
a[2][1] aa a[2][n] aa
a[m] aa a[m][0] aa a[m][1] aa a[m][n] aa
. . .
. . .
. . .
. . .
111
222
333
444
000
666 888
333
222 666 111
555
aaa
a[0] aa a[1] aa a[2] aa
a[3] aa
222 ***
int b[4][4]:
Procedura realizeaz nsumarea elementelor diagonalelor matricei b. ntruct transmiterea
parametrilor se face prin adres, punerea n coresponden este:
a00 a01 a02 a03 a04 a10 a11 a12 a13 a14 a20 a21
1 2 3 4 5 6 7 8 9 10 11 12
b00 b01 b02 b03 b10 b11 b12 b13 b20 b21 b22 b23
a22 a23 a30 a31 a32 a33 a34 a40 a41 a42 a43 a44
13 14 15 16 17 18 19 20 7 1 1 4 2
b30 b31 b32 b33
Prin specificaii se cere
iar prin procedur se obine:

3
0
] 1 , [
i
i b Sb
n loc de Sa = 42 se obine Sb = 34.
n cazul n care structura repetitiv a procedurii efectueaz corect numrul de repetri.
for (i = 0; i < 5; i + +)
S1 = S + b[i][1];
i = 0 localizeaz termenul:
adr (b[0][0] ) = adr(a[0][0])
cont (b[0][0] ) = cont (a[0][0] ) = 1
i = 1
adr(b[1][1]) = adr (b[1][1] ) + (1-0)*4* lg (int) + 1*lg (int) = adr (b[0][0] ) +6*lg (int)
cont (b[1][ 1]) = 6
i = 2
adr (b[2][2] ) = adr (b [0][0] ) + (2-0) * 4* lg (int) + 2*lg (int) = adr (b[0][0]) + 11*lg (int)
cont (b[2][2] ) = 11
i = 3
adr (b[3][3] ) = adr (b [0][0]) + 16*lg (int)
cont (b [3][3] ) = 16
i = 4
adr (b[4] ) = adr (b[0][0} + (4-0) 4* lg*(int) + 4*lg (int) = adr (b[0][0] ) + 21* lg (int)
cont (b [4][4] ) = 7
Valoarea obinut S = 1 + 6 + 11 + 16 + 7 = 41
Cunoaterea modului de adresare i a modului de transmitere a parametrilor, permite
interpretarea cu rigurozitate a oricrui rezultat.
Memorarea unei matrice numai ca form liniarizat, nensoit de informaia dedus din
structura arborescent, implic efectuarea calcului de adresa ori de cte ori este accesat un
element al matricei.
n cazul n care nodului rdcin a, i se rezerv o zon de memorie, iar nodurilor a [0],
a[1], . . . ,a[m] li se asociaz, de asemenea, zona ce se iniializeaz adecvat, regsirea
elementelor se efectueaz folosind calcule de deplasri.
De la relaia:
adr (a[i][j] = adr (a[0][0] ) + [ (i 0)*n + j ]*lg (int)
se ajunge la:
adr (a [i][j] ) = adr (a [i] ) + depl( a [i][j], a [i][0] )
n cazul n care matricea este dens sau ncrcat sau are puine elemente nule sau este full,
dar are elemente ce conin valori particulare, se efectueaz o tratare difereniat.
Matricele simetrice, au proprietatea:
cont (a [i][j] ) = cont (a [j][i] ).
111
222
333
444
000
666 888
333
222 666 111
555
aaa
a[0] aa a[1] aa a[2] aa
a[3] aa
222 ***

4
0
]. 1 , [
i
i a Sa
ceea ce conduce la ideea memorrii numai a elementelor de pe diagonala principal i de sub
aceasta sau de deasupra ei.
Pentru o matrice simetric, a[n][n] cu n*n elemente., impune memorarea a n* (n+1) /2
dintre acestea.
Dac sunt memorate elementele a[i][j], j >= i, i = 0,1,2. . . . n, j = i, i +1, . . .n, astfel:
a00 a01 . . . a0n a11 . . . a1n a22 . . . a2n . . . ann
adr(a [i][j]) = adr ([0][0]) + [(n-0) + (n-1) + . . . (n-i+1) + (j-0) ]*lg (int)
adr (a [i][j] ) = adr (a [0][0] ) + f (i, j, n) * lg (int)
f (i, j, n) reprezint funcia de calcul a deplasrii fa de elementul a [i][0] a elementului a [i][j] :
funcia f (i, j, n) se deduce prin inducie.
Matricea cu linii sau coloane identice, sau cu elemente identice, permit o astfel de
memorare care conduce la o economisire a spaiului de memorie.
Astfel, pentru matricea:
1 1 1 1
1 1 1 1
1 1 1 1
se impun definirile:
nume matrice
numr linii
numr coloane
valoarea elementului repetat (1)
n cazul n care matricea are coninutul:
2 2 2 2 2 2
1 6 2 3 8 6
0 5 4 3 2 1
0 5 4 3 2 1
aceasta are reprezentarea:
Matricele diagonale sunt matricele n care elementele componente apar sub forma:
n
n-1
n-2
1
111
222
333
444
000
666 888
333
222 666 111
555
aaa
a[0] aa a[1] aa a[2] aa
a[3] aa
222 ***
2 0 0 0 0
0 8 0 0 0
0 0 5 0 0
0 0 0 7 0
0 0 0 0 1
A
n acest caz, forma de memorie adecvat, n condiiile n care n urma prelucrrii matricei A,
aceasta nu-i schimb structura, este vectorul.
Un alt tip matrice, cu modaliti specifice de prelucrare, este matricea tridiagonal, care are
forma:
1 8 0 0 0 0
0 9 5 6 0 0
0 0 3 7 2 0
0 0 0 1 8 2
0 0 0 0 4 1
T
Elementele nenule se memoreaz ntr-un masiv unidimensional, iar accesarea lor se
efectueaz dup formula:
adr (t [i][ j] ) = adr (t [0][0] ) + [2* (i 0 ) + j 0 ]* lg (int)
unde, i = 0, 1. . . .n i j =0,1 pentru i =1
j = i 1, i, i + 1 pentru 1 < i < n
j = n 1, n pentru i = n
Matricea triunghiular are elementele nenule fie deasupra, fie sub diagonala principal, iar
stocarea n memorie este asemntoare matricei simetrice.
Pentru matricea triunghiular A cu elementele nenule sub diagonala principal, adresa
elementului a[ i,j] este:
adr (a [i][j] ) = adr (a [0][0] ) + [i* (i 0) /2 + (j 0) ] * lg (int)
Construirea masivului unidimensional se realizeaz n secvena:
k = 0;
for ( i = 0 ; i < n ; i + + )
for ( j = i ; j < n ; j + + )
{
k = k + 1;
s [k] = T [i][j];
};
dac elementele nenule sunt deasupra diagonalei principale sau n secvena:
k = -n* (n+1) /2;
for ( i = n-1 ; i >= 0 ; i-- )
for ( j = i ; j >= 0 ; j-- )
{
s [k] = T [i,j];
k = k 1;
};
dac elementele nenule sunt sub diagonala principal.
n toate cazurile, se urmrete att reducerea lungimii zonei de memorie ocupat, ct i creterea
vitezei de acces la componente. Pentru aceasta, mai nti matricele sunt memorate n extenso,
ca mai apoi dup analiza componentelor s se deduc dac matricele sunt simetrice sau dac au
linii sau coloane constante, cazuri n care se fac alocri adecvate.
Operaiile cu matrice se efectueaz cu algoritmi care iau n considerare forma efectiv n care s-
a fcut memorarea, existnd posibilitatea trecerii rezultatului la un alt tip de stocare n memorie.
De exemplu, dac A este o matrice triunghiular cu elemente nenule sub diagonala principal i
B este o matrice triunghiular cu aceeai dimensiune ca matricea A, dar cu elementele nenule
deasupra diagonalei principale, n cazul adunrii celor dou matrice, rezult o matrice cu toate
elementele nenule., ce este stocat dup regulile acestui tip.
3.3. MATRICE RARE
Pentru a deduce dac o matrice este sau nu rar, se definete gradul de umplere al unei matrice:
100 *
n * m
k
G
unde:
k numrul elementelor nenule;
m -numrul de linii al matricei;
n numrul de coloane al matricei.
n cazul n care k < 0.3*m*n, se consider c matricea este rar.
Problema matricelor rare comport dou abordri:
abordarea static, n care alocarea memoriei se efectueaz n faza de compilare, ceea ce
presupune ca programatorul s cunoasc cu o precizie, bun numrul maxim al elementelor
nenule:
abordarea dinamic, n care alocarea se efectueaz n timpul execuiei, caz n care nu este
necesar informaia asupra numrului de elemente nenule; aceast abordare este dezvoltat n
partea destinat listelor.
Memorarea elementelor matricei rare, presupune memorarea indicelui liniei, a indicelui coloanei
i, respectiv, valoarea nenul a elementului.
Se consider matricea:
0 0 2 8 0
0 9 0 0 0
0 0 0 0 7
0 0 6 0 0
A
Gradul de umplere al matricei A cu numrul de linii m=4, numrul de coloane n = 5 i numrul
elementelor nenule k = 5 este:
25 . 0
4 * 5
5
G
Se definesc 3 vectori astfel:
lin [ ] memoreaz poziia liniei ce conine elemente nenule;
col [ ] - memoreaz poziia coloanei ce conine elemente nenule;
val [ ] memoreaz valoarea nenul a elementelor.
Vectorii se iniializeaz cu valorile:
LIN COL VAL
1 3 6
2 1 7
3 4 9
4 2 8
4 3 2
Pentru efectuarea calculelor cu matrice rare definite n acest fel, un rol important l au vectorii
LIN, COL, iar pentru matricele rare rezultat, trebuiesc definii vectori cu numr de componente
care s asigure i stocarea noilor elemente ce apar.
Astfel, pentru adunarea matricelor rare definite prin:
LIN_a COL_ a VAL_a
1 1 -4
2 2 7
4 4 8
i
LIN_b COL_b VAL_b
1 1 4
2 2 -7
3 2 8
4 1 5
4 3 6
rezultatul final se stocheaz n vectorii:
LIN_C COL_C VAL_C
1 1 0
2 2 0
3 2 8
4 1 5
4 3 6
4 4 8
? ? ?
? ? ?
Vectorii LIN_C, COL_C i VAL_C au un numr de componente definite, egal cu:
DIM (LIN_a) + DIM (LIN_b)
unde, DIM( ) este funcia de extragere a dimensiunii unui masiv unidimensional.
DIM : J -> N
Astfel, dac:
int a[n-m];
DIM (a) = n-m+1
Cum aici este abordat problematica matricelor rare, n mod natural, se produce glisarea
elementelor nenule, obinndu-se n final:
LIN_C COL_C VAL_C
3 2 8
4 1 5
4 3 6
4 4 8
? ? ?
? ? ?
? ? ?
? ? ?
? ? ?
Prin secvene de program adecvate, se face diferena ntre definirea unui masiv bidimensional i
componentele iniializate ale acestora, cu care se opereaz pentru rezolvarea unei probleme
concrete.
De exemplu, vectorii LIN_a i LIN_b au 3, respectiv 5 componente n utilizare, dar la
definire au rezervate zone de memorie ce corespund pentru cte 10 elemente. Rezult c
vectorul LIN_C trebuie definit cu 20 componente nct s preia i cazul n care elementele celor
dou matrice rare au poziii disjuncte.
n cazul operaiilor de nmulire sau inversare, este posibil ca matricele rezultat s nu
mai ndeplineasc cerina de matrice.
n acest scop, se efectueaz calculele cu matrice rezultat complet definite i numai dup
efectuarea calculelor se analizeaz gradul de umplere i dac acesta este redus, se trece la
reprezentarea matricei complete ca matrice rar.
Funciile full() i rar(), au rolul de a efectua trecerea la matricea complet, respectiv la
matricea rar.
Funcia full() conine secvena:
for( i = 0 ; i < n ; i++)
a [LIN _a[i]][COL_a[i]] = val_a[i];
iar funcia rar() conine secvena:
k =1;
for( i = 0 ; i < m ; i++)
for( j = 0 ; j < n ; j++)
if a[i][j] != 0
{
LIN_a[k] = i;
COL_a[k] = j;
val_a[k] = a[I][j];
k = k + i;
};
Funciile full() i rar() sunt una inversa celeilalte.
n cazul n care gradul de umplere nu este suficient de mic nct matricea s fie
considerat rar, pentru memorare se utilizaz o structur arborescent care conine pe nivelul al
doilea poziiile elementelor nule, iar pe nivelul al treilea valorile.
Astfel matricei:
1 8 9 8 6
5 0 9 0 0
0 8 4 2 0
0 0 5 3 7
a
i corespunde reprezentarea:
a
a[0] 1 2 3 a[1] 2 3 4 a[2] 3 5 a[3] *
7 3 5 2 4 8 9 5 6 8 9 8 1
Se elaboreaz convenii asupra modului de stabilire a lungimii vectorului de poziii, fie prin
indicarea la nceput a numrului de componente iniializate, fie prin definirea unui simbol
terminal.
De asemenea. n cazul considerat s-a adoptat convenia ca liniile complete s fie marcate cu '*',
fr a mai specifica poziiile elementelor nenule, care sunt de fapt termenii unei progresii
aritmetice.
Liniarizarea masivelor bidimensionale conduce la ideea suprapunerii acestora peste
vectori. Deci, punnd n coresponden elementele unei matrice cu elementele unui vector,
se pune problema transformrii algoritmilor, n aa fel nct opernd cu elementele vectorilor s
se obin rezultate corecte
pentru calcule matriciale.
Astfel, considernd matricea:
15 14 13 12 11
10 9 8 7 6
5 4 3 2 1
a
prin punerea n coresponden cu elementele vectorului b, s se obin opernd cu acesta din
urm, interschimbul ntre dou coloane oarecare k si j ale matricei.
a00 a01 a02 a03 a04 a10 a11 a20 a21 a22 a23 a24
1 2 3 4 5 6 7 ... 11 12 13 14 15
b0 b1 b2 b3 b4 b5 b6 b10 b11 b12 b13 b14
Dac matricea are M linii i N coloane
adr(a[i][j]) = adr(a[0][0] ) + ( (i-0 )*N+j )*1g(int)
Din modul n care se efectueaz punerea n coresponden a matricei a[ ] cu vectorul b[],
rezult:
aaa
a[1] aa a[2] aa a[n1] aa
a[1,1] aa a[1,2] aa a[1,n2] aa
a[1,1,2] aa a[1,1,n3] aa
a[1,1, . . . 2] aa a[1,1, . . . np] aa
. . . ..
. . . ..
. . . ..
a[1,1,1] aa
. . . . . . . . . . . . . . . . . . . . ..
adr(b[0]) = adr(a[0][0])
deci
adr(a[i][j]) = adr(b[0] )+( (i-0)*N+j )*lg(int) = adr(b[(i-0)*N+j])
Secvena de nlocuire a coloanelor:
for( i = 0 ; i < M ; i++)
{
c = a[i][j];
a[i][j] = a[i][k];
a[i][k] = c;
}
este nlocuit prin secvena:
for( i = 0 ; i < M ; i++)
{
c = b[(i-0)*N+j];
b [(i-0)*N+j] = b[(i-0)*N+k];
b[(i-0)*N+k] = c;
}
Transformarea algoritmilor de lucru cu masive bidimensionale n algoritmi de lucru cu masive
unidimensionale, este benefic, ne mai impunndu-se cerina de transmitere ca parametru
a dimensiunii efective a numrului de linii (dac liniarizarea se face pe coloane), sau a numrului
de coloane. (dac liniarizarea se face pe linii).
n cazul mat ri cel or rare, aceeai probl em revi ne l a interschimbarea valorilor de pe
coloana a treia dintre elementele corespondente ale coloanelor k i j cu posibilitatea inserrii unor
perechi i respectiv tergerii altora.
Pentru generalizare, un masiv n-dimensional rar, este reprezentat prin n+1 vectori, fiecare
permind identificarea coordonatelor elementului nenul, iar ultimul stocnd valoarea acestuia.
n cazul n care se construiete o matrice booleana ce se asociaz matricei rare, odat cu
comprimarea acesteia, se dispun elementele nenule ntr-un vector. Punerea n coresponden a
elementelor vectorului are loc odat cu decomprimarea matricei booleene i analizarea acesteia.
De exemplu, matricei :
0 0 0 9 6 5
0 7 1 0 0 0
0 0 0 0 3 3
0 4 0 0 0 8
A
se asociaz matricea boolean:
0 0 0 1 1 1
0 1 1 0 0 0
0 0 0 0 1 1
0 1 0 0 0 1
B
care prin compactare, ocup primii 3 baii ai unei descrieri, urmai de componentele
vectorului:
C = ( 8, 4, 3, 3, 1, 7, 5, 6, 9).
Compactarea este procedeul care asociaz fiecrei cifre din forma liniarizat a matricei B, un bit.
3.3. Masive multidimensionale
Utilizarea masivelor multidimensionale este impus de tendina unificrii gruprilor
de date omogene, dup diferite criterii ntr-o singur mulime, cu posibilitatea
reconstituirii apartenenei elementelor la fiecare grup.
Dac ntr-o secie sunt 10 muncitori, iar ntreprinderea are 6 secii i se memoreaz
salariile lunare ale acestora pentru 7 ani consecutivi, intuim stocarea volumului
impresionant de salarii folosind un masiv cu 4 dimensiuni, definit prin:
int salarii [10][6][12][7];
iar elementul
salarii [ i ] [ j ] [ k ] [ h ]
a[n
1
][0][n
3
]]]
a[n
1
][0][0] ]]
a[0][0][0] aa
a[n
1
][n
2
][n
3
]]]
a[n
1
][n
2
][0] ]]
a[i][n
2
][0] ]]
iii
jjj
aaa
a[1] aa a[2] aa a[n1] aa
a[1,1] aa a[1,2] aa a[1,n2] aa
a[1,1,2] aa a[1,1,n3] aa
a[1,1, . . . 2] aa a[1,1, . . . np] aa
. . . ..
. . . ..
. . . ..
a[1,1,1] aa
. . . . . . . . . . . . . . . . . . . . ..
a[1,1, . . . 1] aa
aaa
a[3] aa a[2] aa a[1] aa a[0] aa .. ..
... a[2][n] aa a[2][1] aa a[2][0] aaaaaa 555 222 000
333 111 000
.. ..
identific salariul muncitorului i, din secia k, obinut n luna k a anului h.
Obinerea unui nivel mediu
salariu[ . ][ j ][ k ][ h ]
salariu[ . ][ . ][ k ][ h ]
s a l a r i u[ . ] [ . ] [ . ] [ h]
salariu [ . ][ . ][ . ][ . ]
sau a oricrei variante de grad de cuprindere a elementelor colectivitii, este o problem
de:
- definire a masivelor multidimensionale, cu numr de dimensiuni mai redus cu o
unitate, cu dou uniti, cu trei i n final cu patru i apoi, iniializarea lor;
- efectuarea calculelor n cadrul unei secvene de structuri repetitive incluse.
De exemplu, pentru calculele mediilor specificate mai sus se definesc variabilele:
float mjkh_salariu[6][12][7];
float mmkh_salariu[12][7];
float mmmh_salariu[7];
float mmmm_salariu;
Variabilele de control sunt definite pe domeniile:
i[0,9] N k[0,11] N
j[0, 5] N h[0, 6] N
Problema iniializrii se simplific atunci cnd masivele multidimensionale se pun n
coresponden cu un masiv unidimensional, acesta din urm fiind iniializat n cadrul unei
singure structuri repetitive, n care variabila de control are ca domeniu :
[1, 10*6*12*7] N
Modelul grafic asociat masivului multidimensional rmne n continuare structura
arborescent, cu deosebirea c numrul de nivele este mai mare i depinde de numrul de
dimensiuni.
Dac la variabila unidimensional numrul nivelelor este 2, la variabila bidimensional numrul
nivelelor este 3, se deduce c la o variabila p_dimensional, numrul nivelelor este p+1.
Dac se consider masivul a, p_dimensional, avnd pentru fiecare dimensiune definirea:
A[n1][n2][][np],
modelul grafic este:
Localizarea unui element oarecare din masivul p_dimensional de tipul Ti, se efectueaz dup formula:
adr(a[i1][i2][ ][ip] ) = adr(a[l][l][ ][0] ) +
+ f(i1,i2,...,ip; n1,n2,....,np)*lg(Ti)
Spre exemplificare, pentru p = 3 se obine:
a[n
1
][0][n
3
]]]
a[n
1
][0][0] ]]
a[0][0][0] aa
a[n
1
][n
2
][n
3
]]]
a[n
1
][n
2
][0] ]]
a[i][n
2
][0] ]]
iii
jjj
aaa
a[1] aa a[2] aa a[n1] aa
a[1,1] aa a[1,2] aa a[1,n2] aa
a[1,1,2] aa a[1,1,n3] aa
a[1,1, . . . 2] aa a[1,1, . . . np] aa
. . . ..
. . . ..
. . . ..
a[1,1,1] aa
. . . . . . . . . . . . . . . . . . . . ..
a[1,1, . . . 1] aa
aaa
a[3] aa a[2] aa a[1] aa a[0] aa .. ..
... a[2][n] aa a[2][1] aa a[2][0] aaaaaa 555 222 000
333 111 000
.. ..
adr(a[i][j][k]) = adr(a[0][0][0] ) + ((i-0)*n2*n3+ (j-0)*n2+k)*1g(int)
Dac reprezentarea n memorie corespunde paralelipipedului:
i masivele multidimensionale sunt tratate ca matrice rare, numrul vectorilor
"informaionali" care conin indicii pentru corecta localizare a valorilor nenule, sunt n
numr egal cu numrul dimensiunilor masivului de baz. Asocierea arborescenei i
a posibilitii de adresare, respect aceleai reguli ca n cazul masivului bidimensional.
Cnd se fac stocri de informaii referitoare la un grup de elemente, este corect abordarea
n care se specific o serie de informaii precum:
poziia n memorie a primului element;
poziia n memorie a ultimului element;
numrul de elemente sau poziia elementelor n substructura real a masivului.
De exemplu, dac ntr-un masiv tridimensional, n seciunea
corespunztoare lui i = 3, avem pe linia a 2-a elementele:
(l 0 2 0 0 4)
asociem arborescena :
Variabila a[2][1] are o structur convenabil definit, care s poat memora adresele
primei i respectiv ultimei componente de pe nivelul imediat inferior, precum i poziiile
elementelor nenule din linie.
Este convenabil i definirea:
. 3 1 3 6 .
n care, prima informaie de dup adresa primei componente indic numrul
componentelor memorate la nivelul inferior.
Este de dorit ca multitudinea de informaii suplimentare care vin s descrie structura,
fie s menin un grad de ocupare a memoriei ct mai redus, fie s permit un acces mult
mai rapid la informaiile dintr-un masiv multidimensional.
a[n
1
][0][n
3
]]]
a[n
1
][0][0] ]]
a[0][0][0] aa
a[n
1
][n
2
][n
3
]]]
a[n
1
][n
2
][0] ]]
a[i][n
2
][0] ]]
iii
jjj
aaa
a[3] aa a[2] aa a[1] aa a[0] aa .. ..
... a[2][n] aa a[2][1] aa a[2][0] aaaaaa 555 222 000
333 111 000
.. ..
Modul de a pune problema masivelor ca structuri de date omogene, prin folosirea de
exemple, pentru programatori nu reprezint dificultate n nlocuirea valorilor particulare cu
parametrii care conduc la formule generale pentru fiecare clas de probleme n parte.
..............................................................
2. Funcii de intrare i ieire
Pentru realizarea calculului matriceal este necesar existena matricei sau matricelor. Crearea
necorespunztoare a obiectului de lucru, i anume matricea, duce la efecte total neateptate. De
aceea, pentru a fi lipsii de neplceri, atenia acordat acestor funcii este maxim.
n calculul matriceal sunt incluse i funcii de intrare i ieire. Aceste funcii realizeaz:
crearea matricei, fie de la consol ca n cazul bibliotecii matrice.h, fie iniializat cu zero ca n
cazul clasei matrix( constructorul cu parametrii);
afiarea matricei pe ecran.
Cum n biblioteca de funcii matrice.h se lucreaz cu o matrice de dimensiuni constante, iar n
clasa matrix se utilizeaz o variabil de tip pointer, deci dinamic, sunt prezentate ambele moduri
de creare( dinamic i static).
n continuare se prezint funciile care realizeaz creare matricei. n practic se observ, c pe
lng matricea dorit, sunt folosite o serie de matrice ajuttoare cum ar fi matricea unitate,
matricea boolean, matricea cu 1 pe o linie i n rest zero etc.. Funciile de creare a acestor
matrice sunt funcii de intrare, iar afiarea lor este realizat tot cu funcii de ieire.
Matricea este creat n modul de lucru static de la consol folosind funcia din cadrul bibliotecii
matrice.h :
void creation(int *n, int *m, int x[30][30]).
Dup cum se observ tipul funciei este void. Funcia primete ca parametrii urmtoarele
variabile:
int x[30][30]- variabil de tip pointer constant( se aloc memorie pentru 30 de linii i 30 de
coloane, fig.1) la ntreg. Aceasta reprezint matricea care este citit de la tastatur.
int *n- parametru de ieire, numrul de linii a matricei, care este citit de la tastatur. Transferul
se realizeaz prin valoare.
int *m- parametru de ieire, numrul de coloane a matricei, care este citit de la tastatur.
Transferul se realizeaz prin valoare.
Declarnd matricea de dimensiuni constante se aloc de fiecare dat un tablou cu 30 de linii i
30 de coloane:
.. 30 de coloane
..
.
30 de linii
fig. 1
, chiar dac este necesar de exemplu dect o matrice de dou linii i dou coloane( n fig.1
csuele albe reprezint matricea introdus de la tastatur cu dou linii i dou coloane).
Coninutul funciei creation este urmtorul :

printf("\n Matrix lines number:");
scanf("%d",n);
valid_l_c(n);
printf("\n Matrix columns number:");
scanf("%d",m);
valid_l_c(m);
printf("\n The matrix is:");
for(i=0;i<*n;i++)
for(j=0;j<*m;j++)
{
printf("\n The element x[%d][%d] is:",i,j);
k=scanf("%d",&x[i][j]);
valid_no_integer(&x[i][j],k);
}
Se citete numrul de linii i de coloane ale matricei, urmnd introducerea elementelor matricei.
Dup cum se observ fiecare citire este urmat de o validare. Validarea asigur c nu sunt
introduse date eronate( caractere n loc de ntregi, float n loc de ntreg, numrul de linii sau de
coloane depete 30, sau este mai mic sau egal cu zero). Validarea se realizeaz cu ajutorul a
dou funcii:
- void valid_no_integer(int *l, int k);
- void valid_l_c(int *l).
void valid_l_c(int *l)- realizeaz validarea numrului de linii i de coloane introduse de la
tastatur. Funcia primete ca parametru(att de intrare ct i de ieire) un ntreg int *l, care este
transferat ctre alte funcii prin valoare. Coninutul acestei funcii este urmtorul:

if((*l<1)||(*l>30))
do {
printf("\n Error");
gets(linii);
*l=strtod(linii,&endptr);
clrscr();
}
while ((*l<1)||(*l>30)||(*endptr>9));
Aceast validare este foarte puternic deoarece nu permite i introducerea cifrelor urmate de
caractere. Numrul introdus de la tastatur este citit ca un ir de caractere. Se realizeaz
conversia de la ir de caractere la ntreg cu ajutorul funciei int strtod(char, & char*) din cadrul
bibliotecii stdlib.h. n caz de introducere necorespunztoare se afieaz mesajul Error.
void valid_no_integer(int *l, int k)- realizeaz validarea introducerii unui ntreg de la tastatur.
Este folosit n cadrul funciei de creare a matricei n mod static atunci cnd sunt introduse de la
tastatur elementele matricei. Funcia primete ca parametrii dou variabile de tip ntreg i
anume:
- int k- parametru de intrare; funcia scanf ntoarce valoare 0 dac citirea este incorect
sau 1 in cazul citirii corecte. Aceast valoare este primit de funcia valid_no_integer
prin intermediul parametrului k. Dac k este egal cu 0 se afieaz mesajul Error i se
cere o nou introducere a elementului.
- int *l- reprezint valoarea introdus care ndeplinete toate condiiile de validitate.
Transferul parametrului de ieire se realizeaz prin valoare.
Coninutul acestei funcii este urmtorul:
if (k==0)
{
fflush(stdin);
do {
k=1;
printf("\n Error");
k=scanf("%d",l);
fflush(stdin);
}
while(k==0);
}
Spre deosebire de funcia de validare precedent, aceasta nu este la fel de puternic deoarece
permite introducerea numerelor urmate de caractere.
Aadar aceasta a fost funcia de creare de la tastatur a unei matrice n mod static. n continuare
se prezint modul de creare de la consol a unei matrice alocate dinamic. Lucrul cu matrice
alocate dinamic este implementat n clasa matrix. Crearea de la tastatur a unei matrice se
realizeaz n cadrul constructorului implicit al clasei matrix, precum i cu operatorul de shiftare
la dreapta.
Clasa matrix are implementat doi constructori. Unul este implicit fr parametri i realizeaz
introducerea matricei de la tastatur, iar cel de-al doilea primete ca parametrii numrul de linii
i de coloane i creaz matricea cu elementele zero.
Constructorul implicit are urmtoarea configuraie:
matrix::matrix()
{
clrscr();
cout<<"The line number is:";
cin>>n;
clrscr();
cout<<"The column number is:";
cin>>m;
a=aloc_mat(n,m);
clrscr();
cout<<"The matrix is:";
for(int i=0;i<n;i++)
for(int j=0;j<m;j++)
{
cout<<"\n a["<<i<<"]["<<j<<"]=";
cin>>a[i][j];
}
}
Declararea unei matrice cuprinde tipul de dat asociat elementului, numele masivului i
numrul de dimensiuni ale acestuia, adic [ ][ ] ,sau putem declara un pointer la o matrice de
forma int **x.
Folosind a doua metod de declarare a unei matrice folosim att spaiu ct ne trebuie, alocndu-l
dinamic n funcie de cte linii i coloane avem.
Alocarea dinamic presupune utilizarea memoriei ntr-un mult mai eficient i anume se aloc
memorie exact ct este necesar pentru memorarea matricei. Pentru a realiza aceasta se folosete
funcia membru int** aloc_mat(int, int). Dup cum se observ din secvena prezentat mai sus
alocarea memoriei necesare matricei se realizeaz dup introducerea numrului de linii i
coloane. Este foarte important s nu se omit acest pas, altfel rezultatele obinute fiind cu totul
altele. Funcia de alocarea a matricei are ca drept de acces private.
Coninutul ei este urmtorul:
int **pmat;
pmat=(int **)malloc(n*sizeof(int*));
for (int i=0;i<n;i++)
pmat[i]=(int*)malloc(m*sizeof(int));
return pmat;
Funcia primete ca date de intrare numrul de linii n i numrul de coloane m al matricei i
ntoarce un pointer la aceasta.
Matricea X de dimensiuni n=4 i m=3,
1 7 3
0 6 2
9 5 1
8 4 0
, unde n este numrul de linii i m este
numrul de coloane, este alocat n memorie ca n Figura 2.


[2] [1] [0]
[0]
[2] [1] [0] [3]
[2] [1] [0]
[2] [1]
Pointer la
matrice
Figura 2. Alocare dinamic de memorie pentru o matrice
La nceput este alocat zona de memorie pentru un vector de pointeri, care reprezint nceputul
fiecrei linii a matricei. Vectorul conine n componente. Urmeaz alocarea zonei de memorie
pentru fiecare linie a matricei. Linia matricei este alctuit din m elemente. Dup alocarea
spaiului necesar memorrii matricei se continu cu introducerea elementelor matricei.
O alt funcie de intrare este funcia de suprancrcare a operatorului de shiftare la dreapta
>>. Aceasta este declarat ca funcie prieten i are urmtoarea form:
istream &operator>>(istream &c,matrix &a)
{
clrscr();
cout<<"The matrix is:";
for(int i=0;i<a.n;i++)
for(int j=0;j<a.m;j++)
{
cout<<"\n a["<<i<<"]["<<j<<"]=";
c>>a.a[i][j];
}
return c;
}
Operatorul >> realizeaz introducerea elementelor matricei, deoarece citirea unei matrice de
la tastatur este realizat atunci cnd este apelat constructorul cu parametrii, adic constructorul
care iniializeaz numrul de linii i de coloane ale matricei cu datele dorite, precum i
elementele matricei cu zero. Dac este apelat constructorul implicit acesta realizeaz citirea
numrului de linii, numrului de coloane i elementele matricei. Deci recitirea numrului de linii
i de coloane este inutil. A se reine ns faptul c operatorul de shiftare la dreapta este asociat
unor obiecte create cu constructorul cu parametrii.
Constructorul cu parametrii amintit mai sus are structura urmtoare:
matrix::matrix(int k,int l)
{
n=k;
m=l;
a=aloc_mat(n,m);
for(i=0;i<n;i++)
for (j=0;j<m;j++) a[i][j]=0;
}
Aadar au fost prezentate funciile de intrare de la consol la nivel de matrice. Au fost
prezentate n paralel modul de alocare static i varianta dinamic.
n continuare sunt prezentate funciile care creaz matricele speciale. Prezentarea este fcut n
paralel( static i dinamic).
Revenim la biblioteca matrice.h pentru prezentarea funciei de creare a matricei unitate. Acesta
este realizat cu funcia void creating_unit(int *n,int *m, int x[30][30]). Funcia primete ca
parametrii urmtoarele variabile:
- int *n- parametru de ieire i reprezint liniile matricei x;
- int *m- parametru de ieire i reprezint coloanele matricei x;
- int x[30][30]- parametru de ieire i reprezint matricea unitate.
Secvena care realizeaz crearea matricei unitate este urmtoarea:
printf("\n Lines and columns number:");
scanf("%d",n);
valid_l_c(n);
*m=*n;
for(i=0;i<*n;i++)
for(j=0;j<*m;j++)
if(i==j) x[i][j]=1;
else x[i][j]=0;
Matricea unitate presupune o matrice ptratic i de aceea numrul de coloane i linii este citit n
aceeai secven.
n clasa matrix matricea unitate este creat cu ajutorul funciei membru void creating_unit() .
Dei se lucreaz cu o matrice alocat dinamic nu mai este necesar alocarea spaiului de
memorie deoarece acesta a fost pus la dispoziie n momentul apelrii constructorului cu
parametrii. De reinut c toate funciile de creare a matricelor speciale sunt asociate obiectelor
create cu constructorul cu parametrii. Secvena care realizeaz aceasta este urmtoarea:

for (i=0;i<n;i++)
for(j=0;j<=i;j++)
if (i==j) a[i][j]=1;
else a[i][j]=a[j][i]=0;
Deci, singura diferen dintre funcia creating_unit din matrice.h i funcia creating_unit din
clasa matrix este aceea c n funcia membr clasei citirea numrul de linii i de coloane nu mai
este necesar. Numrul este cunoscut, n i m fiind membrii n clas i sunt iniializai prin
apelarea constructorului cu parametrii.
Funcia void creating_column_1(int *n,int *m, int x[30][30]) creaz matricea cu valoarea 1 pe
o coloan dorit, care se introduce de la tastatur, i n rest elementele matricei vor fi zero.
Funcia primete urmtorii parametrii:
- int *n- parametru de ieire i reprezint numrul de linii;
- int *m- parametru de ieire i reprezint numrul de coloane;
- int x[30][30]-parametru de ieire i reprezint matricea ce este obinut prin apelarea
acestei funcii.
Secvena care realizeaz crearea matricei cu valoarea 1 pe o coloan dorit este urmtoarea:
printf("\n The column with elements one is:");
k=scanf("%d",&c);
c--;
for(i=0;i<*n;i++)
for(j=0;j<*m;j++)
{
if(j==c) x[i][c]=1;
else x[i][j]=0;
}
n clasa matrix matricea cu 1 pe coloana dorit este realizat cu funcia membr void
creating_column_1(int c). Acesta are ca parametru de intrare int c care reprezint coloana cu
elementele 1. Secvena care realizeaz crearea matricei este urmtoarea:
if (c<m)
for (i=0;i<n;i++)
for (j=0;j<m;j++)
if (j==c) a[i][c]=1;
else a[i][j]=0;
else cout<<"Column doesn't exist!";
n clas coloana dorit a fi 1 este primit ca parametru n timp ce n funcia din biblioteca
matrice.h este citit de la tastatur.
Funcia void creating_line_1(int *n,int *m, int x[30][30]) creaz matricea cu valoarea 1 pe o
linie dorit, care se introduce de la tastatur, i n rest elementele matricei vor fi zero. Funcia
primete urmtorii parametrii:
- int *n- parametru de ieire i reprezint numrul de linii;
- int *m- parametru de ieire i reprezint numrul de coloane;
- int x[30][30]-parametru de ieire i reprezint matricea ce este obinut prin apelarea
acestei funcii.
Secvena care realizeaz crearea matricei cu valoarea 1 pe o linie dorit este urmtoarea:
printf("\n The line with elements one is:");
k=scanf("%d",&l);
l--;
for(i=0;i<*n;i++)
for(j=0;j<*m;j++)
{
if(i==l) x[i][j]=1;
else x[i][j]=0;
}
n clasa matrix matricea cu 1 pe linia dorit este realizat cu funcia membr void
creating_line_1(int l). Acesta are ca parametru de intrare int l care reprezint linia cu
elementele 1. Secvena care realizeaz crearea matricei este urmtoarea:
if (l<n)
for (i=0;i<n;i++)
for (j=0;j<m;j++)
if (i==l) a[l][j]=1;
else a[i][j]=0;
else cout<<"Line doesn't exist!";
n clas linia dorit a fi 1 este primit ca parametru n timp ce n funcia din biblioteca matrice.h
este citit de la tastatur.
Funcia void creating_sec_diag(int *n, int *m, int x[30][30]) creaz matricea cu 1 pe diagonala
secundar, restul elementelor matricei avnd valoarea 0. Funcia primete ca parametrii
urmtoarele variabile:
- int *n- parametru de ieire i reprezint liniile matricei x;
- int *m- parametru de ieire i reprezint coloanele matricei x;
- int x[30][30]- parametru de ieire i reprezint matricea care are valoarea 1 pe
diagonala secundar.
Secvena care realizeaz crearea matricei cu 1 pe diagonala secundar este urmtoarea:
printf("\n Matrix lines number:");
scanf("%d",n);
valid_l_c(n);
clrscr();
printf("\n Matrix columns number:");
scanf("%d",m);
valid_square(m,*n);
for (int i=0;i<*n;i++)
for(int j=0;j<*n;j++)
if (j==((*n)-i-1)) x[i][j]=1;
else x[i][j]=0;
Matricea cu valoarea 1 pe diagonala secundar presupune matricea ptratic i de aceea este
folosit funcia de validare valid_square(m,*n). Ea verific dac numrul liniilor i cel al
coloanelor este egal. n cazul n care sunt diferite este afiat mesajul Error i se cere o nou
introducere a numrului de coloane.
n clasa matrix matricea cu 1 pe diagonala secundar este creat cu ajutorul funciei membru
void creating_sec_diag(). Secvena care realizeaz aceasta este urmtoarea:
for (i=0;i<n;i++)
for(j=0;j<n;j++)
if (j==(n-i-1)) a[i][j]=1;
else a[i][j]=a[j][i]=0;
Numrul de linii i de coloane este cunoscut, n i m fiind membrii n clas i sunt iniializai prin
apelarea constructorului cu parametrii.
Funcia void creating_0_up_main_diag(int *n, int *m, int x[30][30]) creaz matricea cu 0
deasupra diagonalei principale, restul elementelor matricei fiind citite de la tastatur. Funcia
primete ca parametrii urmtoarele variabile:
- int *n- parametru de ieire i reprezint liniile matricei x;
- int *m- parametru de ieire i reprezint coloanele matricei x;
- int x[30][30]- parametru de ieire i reprezint matricea care are valoarea 0 deasupra
diagonalei principale.
Secvena care realizeaz crearea matricei cu 0 deasupra diagonalei principale este urmtoarea:
printf("\n Matrix lines number :");
scanf("%d",n);
valid_l_c(n);
clrscr();
printf("\n Matrix column number:");
scanf("%d",m);
valid_square(m,*n);
clrscr();
printf("\n The matrix is:\n");
for(int i=0;i<*n;i++)
for(int j=0;j<*m;j++)
if (i>=j)
{
printf("\n x[%d][%d]=",i,j);
l=scanf("%d",&x[i][j]);
valid_no_integer(&x[i][j],l);
}
else x[i][j]=0;
Dinamic, adic n clasa matrix , funcia care realizeaz aceast operaie se numete
creating_0_up_main_diag(). Coninutul funciei este acelai cu cel al funcie de mai sus. Cum
se lucreaz cu obiecte nu mai este necesar citirea numrului de linii i de coloane.
Funcia void creating_0_main_diag(int *n, int *m, int x[30][30]) creaz matricea cu 0 pe
diagonala principal, restul elementelor matricei fiind citite de la tastatur. Funcia primete ca
parametrii urmtoarele variabile:
- int *n- parametru de ieire i reprezint liniile matricei x;
- int *m- parametru de ieire i reprezint coloanele matricei x;
- int x[30][30]- parametru de ieire i reprezint matricea care are valoarea 0 pe
diagonala principal.
Secvena care realizeaz crearea matricei cu 0 pe diagonala principal este urmtoarea:
printf("\n Matrix lines number :");
scanf("%d",n);
valid_l_c(n);
clrscr();
printf("\n Matrix column number:");
scanf("%d",m);
valid_square(m,*n);
clrscr();
printf("\n The matrix is:\n");
for(i=0;i<*n;i++)
for(j=0;j<*m;j++)
if (i!=j)
{
printf("\n x[%d][%d]=",i,j);
l=scanf("%d",&x[i][j]);
valid_no_integer(&x[i][j],l);
}
else x[i][j]=0;
n clasa matrix, funcia care realizeaz aceast operaie se numete creating_0_main_diag().
Funcia este declarat ca funcie membr fr tip. Coninutul funciei este acelai cu cel al
funcie de mai sus. Cum se lucreaz cu obiecte nu mai este necesar citirea numrului de linii i
de coloane.
Funcia void creating_0_under_main_diag(int *n, int *m, int x[30][30]) creaz matricea cu 0
sub diagonala principal, restul elementelor matricei fiind citite de la tastatur. Funcia primete
ca parametrii urmtoarele variabile:
- int *n- parametru de ieire i reprezint liniile matricei x;
- int *m- parametru de ieire i reprezint coloanele matricei x;
- int x[30][30]- parametru de ieire i reprezint matricea care are valoarea 0 sub
diagonala principal.
Secvena care realizeaz crearea matricei cu 0 sub diagonala principal este urmtoarea:
printf("\n Matrix lines number :");
scanf("%d",n);
valid_l_c(n);
clrscr();
printf("\n Matrix column number:");
scanf("%d",m);
valid_square(m,*n);
clrscr();
printf("\n The matrix is:\n");
for(int i=0;i<*n;i++)
for(int j=0;j<*m;j++)
if (i<=j)
{
printf("\n x[%d][%d]=",i,j);
l=scanf("%d",&x[i][j]);
valid_no_integer(&x[i][j],l);
}
else x[i][j]=0;
Dinamic, adic n clasa matrix , funcia care realizeaz aceast operaie se numete
creating_0_under_main_diag().
Funcia creating_0_under_main_diag() este funcie membr fr tip i are acelai coninut cu
funcia creating_0_under_main_diag() din biblioteca matrice.h, mai puin citirea numrului de
linii i de coloane. Iniializarea lor este realizat prin apelarea constructorului cu parametrii.
Funcia void creating_0_sec_diag(int *n, int *m, int x[30][30]) creaz matricea cu 0 pe
diagonala secundar, restul elementelor matricei fiind citite de la tastatur. Funcia primete ca
parametrii urmtoarele variabile:
- int *n- parametru de ieire i reprezint liniile matricei x;
- int *m- parametru de ieire i reprezint coloanele matricei x;
- int x[30][30]- parametru de ieire i reprezint matricea care are valoarea 0 pe
diagonala secundar.
Secvena care realizeaz crearea matricei cu 0 pe diagonala secundar este urmtoarea:
printf("\n Matrix lines number :");
scanf("%d",n);
valid_l_c(n);
clrscr();
printf("\n Matrix column number:");
scanf("%d",m);
valid_square(m,*n);
clrscr();
printf("\n The matrix is:\n");
for(i=0;i<*n;i++)
for(j=0;j<*m;j++)
if (j!=*n-i-1)
{
printf("\n x[%d][%d]=",i,j);
l=scanf("%d",&x[i][j]);
valid_no_integer(&x[i][j],l);
}
else x[i][j]=0;
n clasa matrix, funcia care realizeaz aceast operaie se numete creating_0_sec_diag().
Funcia este declarat ca funcie membr fr tip. Coninutul funciei este acelai cu cel al
funcie de mai sus, mai puin citirea numrului de linii i de coloane care sunt iniializate n
momentul apelrii constructorului cu parametrii.
Funcia void creating_0_up_sec_diag(int *n, int *m, int x[30][30]) creaz matricea cu 0
deasupra diagonalei secundare, restul elementelor matricei fiind citite de la tastatur. Funcia
primete ca parametrii urmtoarele variabile:
- int *n- parametru de ieire i reprezint liniile matricei x;
- int *m- parametru de ieire i reprezint coloanele matricei x;
- int x[30][30]- parametru de ieire i reprezint matricea care are valoarea 0 deasupra
diagonalei secundare.
Secvena care realizeaz crearea matricei cu 0 deasupra diagonalei secundare este urmtoarea:
printf("\n Matrix lines number :");
scanf("%d",n);
valid_l_c(n);
clrscr();
printf("\n Matrix column number:");
scanf("%d",m);
valid_square(m,*n);
clrscr();
printf("\n The matrix is:\n");
for(int i=0;i<*n;i++)
for(int j=0;j<*m;j++)
if (i+j>=*n-1)
{
printf("\n x[%d][%d]=",i,j);
l=scanf("%d",&x[i][j]);
valid_no_integer(&x[i][j],l);
}
else x[i][j]=0;
Dinamic, adic n clasa matrix , funcia care realizeaz aceast operaie se numete
creating_0_up_sec_diag(). Coninutul funciei este acelai cu cel al funcie de mai sus, mai
puin citirea numrului de linii i de coloane deoarece se lucreaz cu obiecte i nu mai este
necesar citirea lor.
Funcia void creating_0_under_sec_diag(int *n, int *m, int x[30][30]) creaz matricea cu 0 sub
diagonala secundar, restul elementelor matricei fiind citite de la tastatur. Funcia primete ca
parametrii urmtoarele variabile:
- int *n- parametru de ieire i reprezint liniile matricei x;
- int *m- parametru de ieire i reprezint coloanele matricei x;
- int x[30][30]- parametru de ieire i reprezint matricea care are valoarea 0 sub
diagonala secundar.
Secvena care realizeaz crearea matricei cu 0 sub diagonala secundar este urmtoarea:
printf("\n Matrix lines number :");
scanf("%d",n);
valid_l_c(n);
clrscr();
printf("\n Matrix column number:");
scanf("%d",m);
valid_square(m,*n);
clrscr();
printf("\n The matrix is:\n");
for(int i=0;i<*n;i++)
for(int j=0;j<*m;j++)
if (i+j<=*n-1)
{
printf("\n x[%d][%d]=",i,j);
l=scanf("%d",&x[i][j]);
valid_no_integer(&x[i][j],l);
}
else x[i][j]=0;
Dinamic, adic n clasa matrix , funcia care realizeaz aceast operaie se numete
creating_0_under_sec_diag().Funcia creating_0_under_sec_diag() este funcie membr fr
tip i are acelai coninut cu funcia creating_0_under_sec_diag() din biblioteca matrice.h, mai
puin citirea numrului de linii i de coloane. Iniializarea este realizat prin apelarea
constructorului cu parametrii.
Funcia void creating_bool_matrix(int n, int m, int x[30][30], int b[30][30]) creaz matricea
boolean. Matricea boolean este matricea ale crei elemente iau valori n mulimea {0,1}.
Deci B=bij, unde i=1,n i j=1,m i bij=

'

altfel
x daca
ij
.... 1
0 .... ..... 0
. Matricea boolean este asociat
ntotdeauna unei alte matrice.
Funcia primete ca parametrii urmtoarele variabile:
- int n- parametru de intrare i reprezint liniile matricei x;
- int m- parametru de intrare i reprezint coloanele matricei x;
- int x[30][30]- parametru de intrare i reprezint matricea creia i se asociaz matricea
boolean;
- int b[30][30]- parametru de ieire i reprezint matricea boolean asociat matricei x.
Secvena care realizeaz crearea matricei booleane este urmtoarea:
for (i=0;i<n;i++)
for(j=0;j<m;j++)
if (a[i][j]==0) b[i][j]=0;
else b[i][j]=1;
n clasa matrix matricea boolean este obinut cu ajutorul funciei membre fr tip
creating_bool_matrix(matrix &). Funcia primete ca parametru de ieire un obiect de tip matrix
care se transfer prin referin. Parametrul de intrare este reprezentat de pionterul this cruia i se
asociaz obiectul de tip matrix , matrice boolean. Funcia este urmtoarea :
void matrix::creating_bool_matrix(matrix &b)
{
for (i=0;i<n;i++)
for (j=0;j<m;j++) if (a[i][j]==0) b.a[i][j]=0;
else b.a[i][j]=1;
}
Dup efectuarea operaiilor este foarte important s vizualizm efectele create. Acesta se
realizeaz cu ajutorul funciilor de ieire. n cazul de fa sunt realizate numai funcii de ieire
ctre monitor. Exist funcii de ieire care transmit informaia unei imprimante, unui fiier sau
mai multor fiiere etc.
Afiarea pe ecran este obinut n cazul lucrului n mod static cu ajutorul funciei void
show_matrix(int n,int m,int x[30][30]), n timp ce n modul de lucru dinamic( implementat n
clasa matrix) este realizat prin suprancrcarea operatorului de shiftare la stnga <<, care
lucreaz acum la nivel de obiecte de tip matrix.
Funcia show_matrix(n,m,x) afieaz pe ecran matricea x. Ea are ca parametrii de intrare :
- int n- numrul de linii;
- int m- numrul de coloane;
- int x[30][30]-matricea care este afiat.
Funcia este urmtoarea:
int i,j;
printf("\n The matrix is:\n");
for (i=0;i<n;i++)
{
for (j=0;j<m;j++)
printf(" %3d ",x[i][j]);
printf("\n");
}
Dac avem de exemplu matricea de 3 linii i 3 coloane, care are elementele 1,2,3,4,5,6,7,8,9
dup apelul acestei funcii pe ecran sunt afiate urmtoarele:
The matrix is:

1 2 3
4 5 6
7 8 9
Operatorul de shiftare la stnga << are ca efect exact acelai mesaj ca i funcia show_matrix.
El a fost suprancrcat ca funcie prieten astfel:
ostream &operator<<(ostream &c,matrix a)
{
int i,j;
clrscr();
if((a.n!=0)&&(a.m!=0))
{
cout<<"\n The matrix is : \n";
for (i=0;i<a.n;i++)
{
cout<<"\n\t";
for (j=0;j<a.m;j++)
c<<"\t"<<a.a[i][j];
}
}
else cout<<"\nNothing to list !!!";
getch();
return c;
}

Calculul matriceal presupune existena matricelor. Aceast problem este rezolvat cu
ajutorul funciilor de intrare. Pentru monitorizarea efectelor obinute n urma operaiilor realizate
sunt foarte necesare funciile de ieire. De aceea funciile de intrare i ieire trebuie tratate cu
toat seriozitatea de ctre programatori.
3. Proceduri de calcul
Aceast categorie de proceduri se refer la operaiile cu matrice. Aici sunt incluse adunarea a
dou matrice, nmulirea a dou matrice, transpunerea unei matrice, diferena dintre dou
matrice, inversa unei matrice. Tot n aceast categorie de proceduri autorii au inclus i operaiile
de adunare, scdere, nmulire i transpunere cu matrice vectorizate. De exemplu, suma a dou
matrice vectorizate presupune transformarea matricelor n vectori, suma efectundu-se acum
ntre doi vectori. Analog se realizeaz i scderea, nmulirea i transpunerea matricei.
n continuare se prezint procedurile care realizeaz operaiile specificate mai sus, precum i
paralela ntre modul de lucru cu o matrice alocat static i una alocat dinamic.
Operaia de nmulire a dou matrice este realizat n dou moduri:
prin funcia
- multiplyng( n1, m1, x, n2, m2, y, z,*n3, *m3)din cadrul bibliotecii matrice.h;
- prin suprancrcarea operatorului * n cadrul clasei matrix.
Funcia void multiplyng(int n1,int m1,int x[30][30],int n2,int m2,int y[30][30],int z[30][30],int
*n3,int *m3) realizeaz nmulirea a dou matrice rezultatul fiind obinut ntr-o a treia matrice.
Parametrii funciei sunt urmtorii:
- int n1,m1- parametrii de intrare; reprezint numrul de linii, respectiv numrul de
coloane ale matricei x;
- int n2,m2- parametrii de intrare; reprezint numrul de linii, respectiv numrul de
coloane ale matricei y;
- int x[30][30],y[30][30]- parametrii de intrare; reprezint matricele care vor fi nmulite;
- int z[30][30]-parametru de ieire i reprezint matricea rezultat al nmulirii celor dou
matrice;
- int n3,m3- parametrii de ieire; reprezint numrul de linii, respectiv numrul de
coloane ale matricei rezultat z. Transferul acestor parametrii se face prin valoare.
Secvena care realizeaz nmulirea celor dou matrice este urmtoarea:
eror=1;
if(m1! =n2) eror=0;
else
{
for(i=0;i<n1;i++)
for(j=0;j<m2;j++)
{
z[i][j]=0;
for(k=0;k<m1;k++)
z[i][j]+=x[i][k]*y[k][j];
}
}
if (eror==0) printf("\n Multiplyng is not posible!");
else {
*n3=n1;
*m3=m2;
}
Dup cum se tie nmulirea a dou matrice se realizeaz dect dac numrul de coloane a
primei matrice este egal cu numrul de linii a celei de-a doua. n funcia prezentat mai sus n
cazul n care nu este ndeplinit aceast condiie se afieaz mesajul Multiplyng is not posible!.
n clasa matrix operaia de nmulire s-a realizat prin suprancrcarea operatorului *.
Suprancrcarea a fost realizat astfel:
matrix matrix::operator*(matrix b)
{
matrix c(n,b.m);
if (m==b.n)
{
for(i=0;i<n;i++)
for(j=0;j<b.m;j++)
{
c.a[i][j]=0;
for(int k=0;k<m;k++)
c.a[i][j]+=a[i]
[k]*b.a[k][j];
}
}
return c;
}
Procedura de suprancrcare ntoarce un obiect de tip matrix i anume rezultatul nmulirii celor
dou matrice, care este creat n interiorul procedurii( obiectul c). Ea primete ca parametru de
intrare un obiect de tip matrix i anume obiectul b. El reprezint operandul din partea dreapt a
nmulirii. Operandul stng al nmulirii este dat de pionterul this. Ca i n cazul funciei din
cadrul bibliotecii matrice.h i n cadrul procedurii de suprncrcare se face testul de validitate a
nmulirii. Alocarea memorie pentru matricea rezultat c este realizat n momentul apelrii
constructorului cu parametrii(matrix c(n,b.m)).
Suma a dou matrice este realizat n cadrul bibliotecii matrice.h i are denumirea
adding(n1,m1,x,n2,m2,y,*n3,*m3,z). Ea are ca parametrii urmtoarele variabile:
- int n1,m1- parametrii de intrare; ei reprezint dimensiunile matricei x(n1 numrul de
linii, m1 numrul de coloane);
- int n2,m2- parametrii de intrare; ei reprezint dimensiunile matricei y;
- int x[30][30],y[30][30]- parametrii de intrare; ei reprezint matricele care sunt adunate;
- int *n3,*m3- parametrii de ieire; reprezint dimensiunile matricei rezultat al adunrii
matricei x cu matricea y(numrul de linii, respectiv numrul de coloane);
- int z[30][30]- parametru de ieire i reprezint matricea n care este pus rezultatul
adunrii celor dou matrice.
Secvena de program care realizeaz suma celor dou matrice este urmtoarea:
eror=1;
if((n1!=n2)|(m1!=m2)) eror=0;
else
{
for(i=0;i<n1;i++)
for(j=0;j<m1;j++)
z[i][j]=x[i][j]+y[i][j];
}
if (eror==0) printf("\n Adding is not posible!");
else {
*n3=n1;
*m3=m2;
}
Ca i la nmulire la adunarea trebuie fcut testul de validitate a sumei, adic numrul de linii i
de coloane al celor dou matrice trebuie s fie egal. n caz contrar se afieaz urmtorul mesaj
Adding is not posible!
Operaia de adunare este realizat n cadrul clasei matrix prin suprancrcarea operatorului +.
Aceasta s-a realizat astfel:
matrix matrix::operator +(matrix b)
{
matrix c(n,m);
if ((n==b.n)&&(m==b.m)){
for(i=0;i<n;i++)
for(j=0;j<m;j++)
c.a[i][j]=a[i][j]+b.a[i][j];
}
return c;
}
Procedura primete ca parametrii de intrare pionterul this i un obiect de tip matrix i anume b.
Rezultatul adunrii este pus n obiectul c. Procedura este de tip matrix i ntoarce astfel obiectul
c. Ca i la nmulire pointerul this este operandul stng al adunrii, iar obiectul de tip matrix, b
este operandul drept al operaiei.
Diferena a dou matrice este realizat n cadrul bibliotecii matrice.h i are denumirea
substracting(n1,m1,x,n2,m2,y,*n3,*m3,z). Ea are ca parametrii urmtoarele variabile:
- int n1,m1- parametrii de intrare; ei reprezint dimensiunile matricei x(n1 numrul de
linii, m1 numrul de coloane);
- int n2,m2- parametrii de intrare; ei reprezint dimensiunile matricei y;
- int x[30][30],y[30][30]- parametrii de intrare; ei reprezint matricele ale cror diferen
este efectuat ;
- int *n3,*m3- parametrii de ieire; reprezint dimensiunile matricei rezultat al diferenei
matricei x cu matricea y(numrul de linii, respectiv numrul de coloane);
- int z[30][30]- parametru de ieire i reprezint matricea n care este pus rezultatul
scderii celor dou matrice.
Secvena de program care realizeaz diferena celor dou matrice este urmtoarea:
eror=1;
if((n1!=n2)|(m1!=m2)) eror=0;
else
{
for(i=0;i<n1;i++)
for(j=0;j<m1;j++)
z[i][j]=x[i][j]-y[i][j];
}
if (eror==0) printf("\n Substracting is not posible!");
else {
*n3=n1;
*m3=m2;
}
Ca i la nmulire la scdere trebuie fcut testul de validitate a sumei, adic numrul de linii i de
coloane al celor dou matrice trebuie s fie egal. n caz contrar se afieaz urmtorul mesaj
Substracting is not posible!
Operaia de scdere este realizat n cadrul clasei matrix prin suprancrcarea operatorului -.
Aceasta s-a realizat astfel:
matrix matrix::operator -(matrix b)
{
matrix c(n,m);
if ((n==b.n)&&(m==b.m)){
for(i=0;i<n;i++)
for(j=0;j<m;j++)
c.a[i][j]=a[i][j]-b.a[i][j];
}
return c;
}
Procedura primete ca parametrii de intrare pionterul this i un obiect de tip matrix i anume b.
Rezultatul scderii este pus n obiectul c. Procedura este de tip matrix i ntoarce astfel obiectul
c. Ca i la nmulire pointerul this este operandul stng al diferenei, iar obiectul de tip matrix, b
este operandul drept al operaiei de scdere.
Operaia de transpunere a unei matrice este realizat n dou moduri:
prin funcia transpose( n, m, x, *n1, *m1, y)din cadrul bibliotecii matrice.h;
prin suprancrcarea operatorului ! n cadrul clasei matrix.
Funcia void transpose(int n,int m,int x[30][30],int *n1,int *m1,int y[30][30]) realizeaz
transpunerea unei matrice rezultatul fiind obinut n alt matrice. Parametrii funciei sunt
urmtorii:
- int n,m- parametrii de intrare; reprezint numrul de linii, respectiv numrul de coloane
ale matricei x;
- int x[30][30]- parametru de intrare i reprezint matricea care este transpus;
- int *n1,*m1- parametrii de ieire; reprezint numrul de linii, respectiv numrul de
coloane ale matricei x transpunse i anume a matricei y. Transferul se face prin valoare;
- int y[30][30]-parametru de ieire i reprezint matricea rezultat al transpunerii matricei;
Secvena care realizeaz transpunerea matricei x este urmtoare:
for(i=0;i<n;i++)
for(j=0;j<m;j++)
y[j][i]=x[i][j];
*n1=m;
*m1=n;
n clasa matrix operaia de transpunere s-a realizat prin suprancrcarea operatorului !.
Suprancrcarea a fost realizat astfel:
matrix matrix::operator!()
{
matrix b(n,m);
int i,j;
for(i=0;i<n;i++)
for(j=0;j<m;j++) b.a[j][i]=a[i][j];
return b;
}
Procedura de suprancrcare ntoarce un obiect de tip matrix i anume rezultatul transpunerii
matricei, care este creat n interiorul procedurii( obiectul b). Ea primete ca parametru de intrare
un pointer la un obiect de tip matrix i anume pointerul this. El reprezint operandul din partea
dreapt a transpunerii. Alocarea memorie pentru matricea rezultat c este realizat n momentul
apelrii constructorului cu parametrii(matrix b(n,m)).
O mare aplicabilitate o are i vectorizarea unei matrice. Aceasta s-a concretizat prin funcia void
matrix_line(int a[30][30],int n,int m,int x[],int *k) din cadrul bibliotecii matrice.h.
Aceast funciei preia o matrice i o transform ntr-un vector de n*m+2 componente.
Traversarea matricei se face pe linii, deci n vector vor fi regsite elementele matricei ca i cnd
am cap la cap fiecare linie. Dimensiunea vectorului este cu dou componente mai mare dect
numrul de elemente ale matricei deoarece pe ultimele dou poziii se pstreaz numrul de
linii, respectiv numrul de coloane ale matricei. Este important pstrarea dimensiunilor
matricei pentru o eventual operaie invers( de la vector la matrice) sau pentru operaiile de
adunare, scdere, transpunere i nmulire cu matrice vectorizate.
Funcia primete urmtorii parametrii:
- int a[30][30]- parametru de intrare i reprezint matricea care este vectorizat;
- int n,m- parametrii de intrare; reprezint dimensiunile matricei a;
- int x[]- parametru de ieire i reprezint vectorul n care este transformat matricea a;
- int *k- parametru de ieire i reprezint dimensiunea vectorului x. Transferul se face
prin valoare.
Funcia are urmtoarea structur:
void matrix_line(int a[30][30], int n, int m, int x[], int *k)
{
int i,j;
(*k)=0;
for (i=0;i<n;i++)
for(j=0;j<m;j++)
{
x[*k]=a[i][j];
(*k)++;
}
x[*k]=n;
(*k)++;
x[*k]=m;
(*k)=(n*m)+2;
}
n clasa matrix funcia care realizeaz vectorizarea unei matrice se numete matrix_line. Ea are
urmtoarea form int* matrix_line(int &k). Funcia este funcie membr a clasei i are tipul int*
returnnd aadar un vector. Spre deosebire de funcia matrix_line din biblioteca matrice.h n
funcia membr clasei att vectorul ct i matricea sunt declarate dinamic. Asta presupune
alocarea memorie n interiorul funciei pentru vectorul rezultant.
Funcia este urmtoarea:
int*matrix:: matrix_line( int *k)
{
int i,j,*x;
x=aloc_vec(n,m);
(*k)=0;
for (i=0;i<n;i++)
for(j=0;j<m;j++)
{
x[*k]=a[i][j];
(*k)++;
}
x[*k]=n;
(*k)++;
x[*k]=m;
(*k)=(n*m)+2;
return x;
}
Pentru a nelege mai bine algoritmul, consider urmtorul masiv de 3 linii i 3 coloane:


9 8 7
6 5 4
3 2 1
Deci aceasta este matricea. n urma apelrii funciei matrix_line fie din biblioteca matrice.h, fie
din clasa matrix se obine urmtorul vector:
1 2 3 4 5 6 7 8 9 3 3
Dup cum se observ apar dou componente diferite de elementele matricei. Ele reprezint
dimensiunile matricei i vor ntotdeauna memorate pe ultimele dou poziii din vector, de unde
i dimensiunea 3*3+2 componente.
Suma a dou matrice vectorizate a fost de asemenea realizat n dou moduri:
- matricele vectorizate sunt pointeri constani, varianta din biblioteca matrice.h;
- matricele vectorizate sunt pointeri variabili, varianta din clasa matrix.
Prima variant s-a concretizat prin funcia void add_line_matr(int x[],int l1,int y[],int l2,int
z[],int *k).
Funcia primete urmtorii parametrii:
- int x[],y[]- parametri de intrare i reprezint matricele vectorizate care vor fi nsumate;
- int l1,l2- parametrii de intrare; reprezint dimensiunile matricei vectorizate x, respectiv a
matricei vectorizate y;
- int z[]- parametru de ieire i reprezint vectorul n care vor fi nsumate cele dou
matrice;
- int *k- parametru de ieire i reprezint dimensiunea vectorului z. Transferul se face prin
valoare.
Funcia are urmtoarea structur:
void add_line_matr(int x[],int l1,int y[],int l2,int z[],int *k)
{
int i,j;
*k=0;
if ((x[l1-2]==y[l2-2])&&(x[l1-1]==y[l2-1]))
{
for(i=0;i<l1-2;i++) z[i]=x[i]+y[i];
z[i]=x[l1-2];
i++;
z[i]=x[l1-1];
*k=l1;
}
}
n clasa matrix funcia care realizeaz nsumarea a dou matrice vectorizate se numete
row_matrix_elem_sum. Ea are urmtoarea form int* row_matrix_elem_sum( matrix ,int *,int
*,int *). Funcia este funcie membr a clasei i are tipul int* returnnd aadar un vector. Spre
deosebire de funcia add_line_matr din biblioteca matrice.h n funcia membr clasei att
vectorul ct i matricea sunt declarate dinamic. Asta presupune alocarea memorie n interiorul
funciei pentru vectorul rezultant.
Funcia primete urmtorii parametrii:
- parametrii de intrare- this, matrix b, int *x, int *y; ei reprezint matricele care au fost
vectorizate, respectiv vectorii n care au fost transformate;
- parametrii de ieire- int *k care reprezint dimensiunea vectorului rezultat al adunrii
vectorilor x i y.
Aceasta este funcia:
int * matrix::row_matrix_elem_sum( matrix b,int *x,int *y,int *k)
{
int *z;
z=aloc_vec(n,m);
*k=0;
if ((n==b.n)&&(m==b.m))
{
for(i=0;i<n*m;i++) z[i]=x[i]+y[i];
z[i]=n;
i++;
z[i]=m;
*k=(n*m+2);
}
return z;
}
Avem urmtorul exemplu:

A=
1 3
12 2
B=
5 43
4 56
Dup vectorizare se obine :X=2 12 3 1 2 2
Y= 56 4 43 5 2 2
Dup apelarea funciei add_line_matr(x,6,y,6,z,&k) se obine matricea vectorizat Z=58 16 46 6
2 2
Operaia de scdere este realizat prin funciile void substr_line_matr (int x[],int l1,int y[],int
l2,int z[],int k) din matrice.h i int*matrix::row_matrix_elem_substr( matrix b,int *x,int *y,int
*k) din clasa matrix. Explicaiile sunt identice ca la operaia de adunare. Funciile sunt
prezentate n anexa de la sfritul lucrrii.
nmulirea a dou matrice vectorizate alocate static se realizeaz prin procedura void
multiply_line_matr(int x[],int l1,int y[],int l2,int z[],int *k). Funcia primete urmtorii
parametrii:
- int x[],y[]- parametri de intrare i reprezint matricele vectorizate care vor fi nmulite;
- int l1,l2- parametrii de intrare; reprezint dimensiunile matricei vectorizate x, respectiv a
matricei vectorizate y;
- int z[]- parametru de ieire i reprezint vectorul n care vor fi nmulite cele dou
matrice;
- int *k- parametru de ieire i reprezint dimensiunea vectorului z. Transferul se face prin
valoare.
Funcia are urmtoarea structur:
void multiply_line_matr(int x[],int l1,int y[],int l2,int z[],int *k)
{
int q,r,i,j,lineA,columnA,lineB,columnB;
int *v,*w,l,vb,vb1,matrix[30][30];
lineA=x[l1-2];
columnA=x[l1-1];
lineB=y[l2-2];
columnB=y[l2-1];
if ((columnA==lineB))
{
line_matrix(y,l2,matrix,&q,&r);
matrix_line(matrix,q,r,v,&l);
vb=0;*k=0;
while(vb*columnA!=(columnA*lineA))
{
j=0;
for (i=(vb*columnA);i<((vb+1)*columnA);i++)
{
w[j]=x[i];j++;
}
vb1=0;
while ((vb1*lineB)!=(lineB*columnB))
{
j=0;z[*k]=0;
for(i=(vb1*lineB);i<((vb1+1)*lineB);i++)
{
z[*k]+=w[j]*v[i];
j++;
}
vb1++;
(*k)++;
}
vb++;
}
z[*k]=lineA;
(*k)++;
z[*k]=columnB;
*k=columnB*lineA+2;
}
else *k=0;
}
Este necesar retransformarea n matrice a vectorului y. Aceasta se realizeaz cu funcia:
void line_matrix(int x[],int l,int a[30][30],int *n,int *m)
{
int i,j,p;
(*n)=x[l-2];
(*m)=x[l-1];
p=0;
for(i=0;i<*n;i++)
for(j=0;j<*m;j++) {
a[i][j]=x[p];
p++;
}
}
Dup aceast transformare vom vectoriza matricea matrix obinut anterior prin apelarea
funciei line_matrix(y,l2,matrix,&q,&r). Aceast vectorizare este de fapt o transpunere a
matricei matrix. Operaia se realizeaz cu funcia void matrix_line_top(int a[30][30],int n,int
m,int x[],int *k). Sau realizat aceste operaii pentru a uura nmulirea efectiv a celor dou
matrice vectorizate.
Algoritmul este simplu, folosindu-se variabilele vb i vb1 pentru a ti cnd se termin
componentele matricei. Altfel exist riscul de nmuli i ultimele dou poziii ale vectorilor.
Tot cu ajutorul acestor variabile se disting liniile i coloanele matricelor transpuse n vectorii x,
respectiv y. Acest lucru este necesar pentru a obine rezultatul dorit i anume o matrice sub
form vectorial. Variabilele lineA, columnA sunt folosite pentru pstra numrul de linii,
respectiv numrul de coloane al matricei transformate n vectorul x. Analog variabilele lineB,
respectiv columnB.
n clasa matrix nmulirea a fost realizat n funcia int * row_matrix_elem_multpl(matrix b,int
*x,int *y,int k). Pentru a evita folosirea a multor variabile s-a folosit ca parametrii de intrare i
cele dou matrice( pointerul this i matrix b), precum i vectorii n care au fost transformate int
* x, respectiv int *y. Algoritmul este acelai cu cel al funciei multiply_line_matr, cu meniunea
c n clasa matrix vectorii sunt declarai dinamic i de aceea este necesar alocarea spaiului
necesar fiecruia.
Funcia membr clasei este urmtoarea:
int * matrix::row_matrix_elem_multpl(matrix b,int *x,int *y,int *k)
{
int vb,vb1,**matrix,*v,*w,*z;
z=aloc_vec(m,b.n);
if ((m==b.n))
{
matrix=b.row_to_matrix(y);
v=b.row_matrix2(matrix);
vb=0;*k=0;
while(vb*m!=(n*m))
{
j=0;
w=(int *)malloc(m*sizeof(int));
for (i=(vb*m);i<((vb+1)*m);i++) {w[j]=x[i];j++;}
vb1=0;
while ((vb1*b.n)!=(b.n*b.m))
{
j=0;
z[*k]=0; for(i=(vb1*b.n);i<((vb1+1)*b.n);i++)
{
z[*k]+=w[j]*v[i];
j++;
}
vb1++;
(*k)++;
}
vb++;
}
z[*k]=n;
(*k)++;
z[*k]=b.m;
*k=b.m*n+2;
}
else *k=0;
return z;
}
Transpusa unei matrice vectorizate a fost folosit de fapt n funcia de nmulire pentru a uura
munca. Funcia este urmtoarea:
void transpose_line_matrix(int x[],int k,int *z,int *l1)
{
int *v,a[30][30],q,r,l,i;
line_matrix(x,k,a,&q,&r);
matrix_line(a,q,r,v,&l);
for (i=0;i<l-2;i++) z[i]=v[i];
z[i]=r;
i++;
z[i]=q;
(*l1)=q*r+2;
}
Funcia membr a clasei matrix este de tip int* i returneaz astfel vectorul obinut n urm
transpunerii matricei vectorizate. Ea mai primete ca parametru de intrare dect matricea
vectorizat i dimensiunea vectorului. Funcia este urmtoarea:
int * matrix::row_matrix_elem_transpose(int *x,int *k)
{
int **matrix,*v,*z;
z=aloc_vec(m,n);
*k=0;
matrix=row_to_matrix(x);
v=row_matrix2(matrix);
for (i=0;i<n*m;i++) z[i]=v[i];
z[i]=m;
i++;
z[i]=n;
(*k)=n*m+2;
return z;
}
Cum declararea variabilelor s-a fcut dinamic apare necesitatea alocrii spaiului de memorie
pentru vectorul rezultat. Alocarea memorie se face prin intermediul funciei membre cu acces
privat aloc_vec(int, int). Aceast funcie este urmtoarea:
int* matrix::aloc_vec(int n,int m)
{
int *pvec;
pvec=(int *)malloc((n*m+2)*sizeof(int));
return pvec;
}
Aloc spaiul de memorie pentru un vector de dimensiunea n*m+2.
Datorit necesitilor ulterioare sunt incluse n biblioteca matrice.h i funciile
creation_float(&n,&m,x), creating_unit_float(n,m,x) i show_matrix_float(n,m,x). Diferena
dintre funciile prezentate mai sus i funciile din acest capitol const n faptul c tipul
elementelor matricei nu este ntreg. Matricea este declarat astfel: float x[30][30].
Aadar comentariile pentru aceste funcii sunt identice cu cele corespondente funciilor
prezentate n acest capitol( masivul are elemente ntregi).
Aceste funcii prezentate mai sus au fost grupul procedurilor de calcul care vor fi utilizate n
capitolele urmtoarea pentru a exemplifica aplicabilitatea calculului matriceal.
4.Funcii de comparare
Funciile de comparare a matricelor sunt folosite cu scopul de afla informaii despre o matrice
sau un set de matrice din punctul de vedere al tipului unei matrice, a tipului elementelor ce o
compun sau a numrului de apariii n cadrul acelei matrice al unei chei definite de utilizator.
Funia symmet verific dac o matrice ptratic este simetric. Funcia primete ca date de
intrare numrul de linii i de coloane al matricei, adic n i m, i matricea X care este verificat.
Matricea este definit static. Funcia returneaz adresa unei variabile de tip ntreg, *er, unde se
scrie 1 dac matricea este simetric i 0 dac matricea nu este simetric. De asemenea funcia
verific i dac matricea nu este patratic, caz n care la adresa acelei variabile se scrie 0.
Funcia este :
void symmet(int n,int m,int x[30][30],int *er)
{
int i,j;
//verific dac matricea este ptratic
if(n!=m) printf("\n The matrix must be a square !");
else
{
*er=1;
for(i=0;i<n;i++)
for(j=0;j<m;j++)
if(i<j) if(x[i][j]!=x[j][i]) *er=0;
if (*er==0) printf("\n The matrix is not symmetrical!");
else printf("\n The matrix is symmetrical!");
}
}
Funcia check_unit verific dac matricea este sau nu matricea unitate. Funcia are ca
parametrii de intrare dimensiunile matricei X, definit static, care este verificat i anume n,
numrul de linii, i m, numrul de coloane. Printre aceti parametrii se afl i adresa unei
variabile de tip ntreg, *er, unde se scrie 1, dac matricea este matricea unitate ori 0,dac
matricea nu este ptratic sau nu este matricea unitate.
Funcia este :
void check_unit(int n,int m,int x[30][30],int *er)
{
int i,j;
//verific dac matricea este ptratic
if(n!=m) printf("\n The matrix must be a square !");
else
{
*er=1;
for(i=0;i<n;i++)
for(j=0;j<m;j++)
if(x[i][j]!=1) *er=0;
if (*er==0) printf("\n The matrix is not a unit matrix");
else printf("\n The matrix is a unit matrix");
}
}
Funcia check_no verific dac un numr dat de utilizator funciei este sau nu n matrice.
Parametrii de intrare ai funciei sunt dimensiunile unei matrice definit static, n numrul de linii,
m numrul de coloane i matricea X. Rezultatul verificrii este cunoscut prin intermediul unei
variabile de tip ntreg eror, a crei adres este parametru de intrare al funciei. Dac numrul
cutat este n matrice, eror are valoare 1 i dac numrul cutat nu este n matrice atunci eror
are valoarea 0. Numrul ce este cutat este citit n interiorul funciei.
Funcia este :
void check_no(int n,int m,int x[30][30],int *eror)
{
int i,j,k,z;
// se citete de la tastatur numrul de cutat
printf("\n The searched number is::");
*eror=0;
k=scanf("%d",&z);
//are loc validarea lui
valid_no_integer(&z,k);
for(i=0;i<n;i++)
for(j=0;j<m;j++)
if(x[i][j]==z)
{
// se afieaz linia i coloana unde este gsit numrul
printf("\n Searched number is on line %d and column %d ",i,j);
*eror=1;
}
if(*eror==0) printf("\n The number is not in matrix!");
}
Funcia check_line_column primete ca date de intrare dimensiunile unei matrice, adic
numrul de linii n i numrul de coloane m, i matricea respectiv X, definit static. Funcia
verific dac un vector citit de la tastatur n interiorul funciei reprezint sau nu o coloan a
matricei. O variabil numit eror, a crei adres este parametru de intrare al funciei, ia valorile
1 sau 0 dac este adevrat sau dac nu.
La citirea vectorului, elementele sale sunt validate cu ajutorul funciei valid_no_integer.
Funcia este :
void check_line_column(int n,int m,int x[30][30],int *eror)
{
int i,j,h[30],k;
//se citete vectorul i se valideaz elementele sale
printf("\n The line to be checked is :");
//dimensiunea vectorului este n
for(i=0;i<n;i++)
{
printf("\n The element h[%d] is:",i);
k=scanf("%d",&h[i]);
valid_no_integer(&h[i],k);
}
//se verific dac vectorul citit este sau nu coloan a matricei
for(j=0;j<m;j++)
{
*eror=1;
for(i=0;i<n;i++)
if(x[i][j]!=h[i]) *eror=0;
if(*eror==1)
{
printf("\n The line is the column %d",j);
k=2;
}
}
if(k!=2) printf ("\n The line doesn't represent a column in the matrix");
}
Funcia check_line_line verific dac un vector citit de la tastatur n interiorul funciei este
sau nu linie intr-o matrice X, definit static,i care este parametru de intrare al funciei. Ca date
de intrare funcia mai are dimensiunile matricei, n linii i m coloane, i adresa unei variabile de
tip nreg eror, unde se scrie 1 n caz de adevr i 0 n caz de neadevr.
La citirea vectorului, elementele sale sunt validate cu ajutorul funciei valid_no_integer.
Funcia este:
void check_line_line(int n,int m,int x[30][30],int *eror)
{
int i,j,h[30],k;
//se citete vectorul i se valideaz elementele sale
printf("\n The line to be checked is:");
//dimensiunea vectorului este m
for(j=0;j<m;j++)
{
printf("\n The element h[%d] is:",j);
k=scanf("%d",&h[j]);
valid_no_integer(&h[j],k);
}
//se verific dac vectorul citit este sau nu coloan a matricei
for(i=0;i<n;i++)
{
*eror=1;
for(j=0;j<m;j++)
if(x[i][j]!=h[j]) *eror=0;
if(*eror==1)
{
printf("\n The line is the line %d",i);
k=2;
}
}
if(k!=2) printf ("\n The line doesn't represent a line in the matrix");
}
Urmtoarele 2 funcii check_columns i check_lines verific dac o matrice are sau nu
coloane respectiv linii egale. Ambele funcii au ca parametrii : numrul de linii al matricei, n,
numrul de coloane al amtricei, m, matricea X definit static i adresa unei variabile de tip
ntreg, eror, unde se scrie 1, dac se verific egalitatea sau 0, dac nu se verific.
Principiul care st la baza celor dou funcii este faptul c se ia fiecare coloan, respectiv
linie, i se compar cu urmtoarele afindu-se coloanele sau liniile egale.
Funciile sunt :
void check_columns(int n,int m,int x[30][30],int *eror)
{
int i,j,k,l;
*eror=1;
l=0;
// se iau coloanele pe rnd
for(j=0;j<m-1;j++)
{
*eror=1;
//se verific cu urmtoarele
for(k=j+1;k<m;k++)
{
*eror=1;
for(i=0;i<n;i++)
if(x[i][j]!=x[i][k]) *eror=0;
if(*eror==1)
{
l=1;
//se afieaz coloanele egale
printf("\n Coloana Column%d is equal with column %d ",j,k);
}
}
}
if(l==0) printf("\n The matrix has no equal columns");
}
i respectiv :
void check_lines(int n,int m,int x[30][30],int *eror)
{
int i,j,k,l;
*eror=1;
l=0;
//se iau liniile pe rnd
for(i=0;i<n-1;i++)
{
*eror=1;
// fiecare linie se compar cu urmtoarele linii
for(k=i+1;k<n;k++)
{
*eror=1;
for(j=0;j<m;j++)
if(x[i][j]!=x[k][j]) *eror=0;
if(*eror==1)
{
l=1;
// se afieaz liniile egale
printf("\n Line %d is equal with line %d ",i,k);
}
}
}
if(l==0) printf("\n The matrix has no equal lines");
}
Funcia key_appar_no avnd ca parametrii numrul de linii i de coloane al unei matrice, n
respectiv m, matricea respectiv X, definit static, i adresa unei variabile ntregi v ; numr de
cte ori un numr citit de la tastatur se afl n acea matrice. Numrul de apariii memorat la
adresa variabilei v.
Numrul citit de la tastatur este validat cu ajutorul funciei valid_no_integer.
Funcia este :
void key_appar_no(int n,int m,int x[30][30],int *v)
{
int i,j,k,c,l;
clrscr();
//se citete numrul de la tastatur i se valideaz
printf("\n Type the key:");
l=scanf("%d",&c);
valid_no_integer(&c,l);
k=0;
//se numr apariiile sale n matrice
for (i=0;(i<n);i++)
for (j=0;j<m;j++)
if (x[i][j]==c) k++;
if (k==0) printf ("\nThe key does not appear in the matrix!");
else
{
*v=k;//se memoreaz numrul apariiilor
printf("\nThe key appears in the matrix for %d times",*v);
}
getch();
}
Urmtoarele dou funcii key_appar_no_line i key_appar_no_column numra de cte ori
apare numr citit de la tastatur ntr-o linie respectiv coloan indicat de utilizator. Ambele
funcii au aceiai parametrii : n numrul de linii al matricei, m numrul de coloane al matricei,
matricea X definit static i adresa unei variabile ntregi v. La adresa acelei variabile se scrie
numrul de apariii al cheii de cutat n coloana sau linia indicat de utilizator.
Funciile sunt :
void key_appar_no_line(int n,int m,int a[30][30],int *v)
{
int i,j,k,c,q,l;
clrscr();
//se citete cheia de cutat i se valideaz
printf("\n Type the key:");
l=scanf("%d",&c);
valid_no_integer(&c,l);
// se indic linia n care se caut
printf("\n Type the line :\t");
scanf("%d",&q);
k=0;
//se numr apariiile cheii
for (j=0;j<m;j++)
if (a[q][j]==c) k++;
if (k==0)
{
printf ("The key %d does not appear in the line %d!",c,q);
*v=k;//se memoreaz numrul apariiilor
}
else
{
*v=k; //se memoreaz numrul apariiilor
printf ("The key %d does appear in the line %d for %d times",c,q,*v);
}
}
i respectiv
void key_appar_no_column(int n,int m,int a[30][30],int *v)
{
int i,j,k,c,q,l;
clrscr();
//se citete cheia de cutat i se valideaz
printf("Type the key:");
scanf("%d",&c);
valid_no_integer(&c,l);
// se indic coloana n care se caut
printf("\n Type the column:\t");
scanf("%d",&q);
k=0;
//se numr apariiile cheii
for (i=0;i<n;i++)
if (a[i][q]==c) k++;
if (k==0)
{
printf ("The key %d does not appear in the column %d!",c,q);
*v=k; //se memoreaz numrul apariiilor
}
else
{
*v=k; //se memoreaz numrul apariiilor
printf ("The key %d does appear in the column %d for %d times",c,q,*v);
}
}
Pe lng aceste funcii aflate n biblioteca matrice.h, n clasa matrix au fost suprancrcai
operatorii % i = = , pentru a se efectua operaii de comparare asupra obiectelor de tip matrix.
Operatorul % suprancrcat face acelai lucru ca i funcia symmet verificnd dac o matrice este
simetric.
Operatorul == verific dac dou obiecte de tip matrix sunt egale, adic verific dac dou
matrice sunt egale. Operatorul primete ca date de intrare adresa obiectului cu care se compar
i returneaz 0 dac cele dou obiecte sunt diferite sau 1 dac obiectele sunt egale.
Secvena de cod care realizeaz acest lucru este :
int matrix::operator ==(matrix &b)
{
int k=0;
//prima dat se verific dimensiunile celor dou obiecte
if ((n==b.n)&&(m==b.m))
{
//dac au aceeai dimensiune, se verific element cu element
for(i=0;i<n;i++)
for(j=0;j<m;j++) if (a[i][j]!=b.a[i][j]) k=1;
if (k==1) return 0;//obiectele sunt diferite
else return 1;//obiectele sunt egale
}
else return 0;
}
Funciile prezentate mai sus i care aparin bibliotecii sunt prezente i n cadrul clasei matrix ,
dar ele nu mai au parametrii de intrare, ele returnnd valori de tip integer.
Modelele lor sunt :
int check_line_column();
int check_line_line();
int check_columns();
int check_lines();
int check_unit();
int key_appar_no(int);
int key_appar_no_line(int,int);
int key_appar_no_column(int,int);
Pe lng aceste modificri de suprafa suferite de definirile funciilor pentru a se lucra cu
obiecte, algoritmul folosit de fiecare funcie este acelai n cadrul bibliotecii i clasei.
5.Funcii de prelucrare n matrice
Funciile de prelucrare n matrice sunt acele funcii care fac diferite operaii matematice,
operaii de interschimbare, numrare, modificare, tergere, nlocuire asupra elementelor unei
matrice modificnd-o n cele mai multe cazuri.
Toate aceste funcii sunt diferite ntre ele, nu numai prin ceea ce fac ele, ci i prin parametrii
care i primesc sau prin valorile returnate. Totui toate funciile din acest capitol primesc ca date
de intrare un set standard de date i anume : n numrul de linii, m numrul de coloane i
matricea respectiv X sau A, matricea fiind definit static.
Urmtoarele 2 funcii primesc ca date de intrare dimensiunile matricei, adic n numrul de
linii i m numrul de coloane, i matricea respectiv X , definit static. Funciile sunt
bubble_sort_line i bubble_sort_column i ele sorteaz o linie respectiv coloan a matricei prin
metoda bulelor. Linia respectiv coloana de sortat este dat funciei n interiorul ei de ctre
utilizator. Cum aceste dou funcii nu modific dimensiunile matricei i lucreaz doar cu
valorile elementelor matricei, funciile nu returneaz nici o valoare.
Prima funie este :
void bubble_sort_line(int n,int m,int x[30][30])
{
int i,j,k,a,l,b;
//se citete numrul linie de sortat
printf("\n The sorting line is:");
b=scanf("%d",&l);
//se sorteaz cu metoda bulelor
for (j=0;j<m-1;j++)
for(k=j+1;k<m;k++)
if (x[l-1][j]>x[l-1][k])
{
for (i=0;i<n;i++)
{
a=x[i][j];
x[i][j]=x[i][k];
x[i][k]=a;
}
}
}
iar ce de-a doua funcie este :

void bubble_sort_column(int n,int m,int x[30][30])
{
int i,j,k,a,c,b;
printf("\n The sorting column is:");
//se citete numrul coloanei de sortat
b=scanf("%d",&c);
//se sorteaz cu metoda bulelor
for (i=0;i<n-1;i++)
for(k=i+1;k<n;k++)
if (x[i][c-1]>x[k][c-1])
{
for (j=0;j<m;j++)
{
a=x[i][j];
x[i][j]=x[k][j];
x[k][j]=a;
}
}
}
Funciile void lines_sum i columns_sum afl suma elementelor matricei de pe fiecare linie,
respectiv de pe fiecare coloan. Pe lng setul standard de date de intrare (n, m, i X), funciile
primesc un vector definit static cu maxim 30 de elemente, int y[30], i adresa unei variabile de
tip ntreg, int *v
n acel vector se vor memora sumele de pe fiecare linie, respectiv coloan, iar la adresa
variabilei se scrie dimensiunea vectorului, care este egala cu numrul de linii/coloane. Astfel la
terminarea apelului funciei avem vectorul de sume i dimensiunea lui.
Funciile sunt :
void lines_sum(int n,int m,int x[30][30],int y[30],int *v)
{
int i,j,s;
for(i=0;i<n;i++) //se calculeaz sumele i se scriu n vector
{
s=0;
for(j=0;j<m;j++)
s+=x[i][j];
y[i]=s;
}
//se reine dimensiunea vectorului
*v=n;
}
i respectiv :
void columns_sum(int n,int m,int x[30][30],int y[30],int *v)
{
int i,j,s;
for(j=0;j<m;j++)
{
s=0;
for(i=0;i<n;i++)
s+=x[i][j];
y[j]=s; //se calculeaz sumele i se scriu n vector
}
*v=m; //se reine dimensiunea vectorului
}
Urmtoarea pereche de funcii interchange_lines i interchange_columns interschimb
dou linii, respectiv dou coloane ale matricei ntre ele. i aceste dou funcii primesc
dimensiunile matricei, n i m, i matricea X n care se lucreaz. Ele mai au ca date de intrare i
poziiile n matrice al celor dou linii/coloane care se interschimb. n interiorul funciilor
exist validri ale acestor poziii.
Cele dou funcii sunt :
void interchange_lines(int n,int m,int x[30][30],int a,int b)
{
int i,j,var;
//validarea celor dou pozitii ale liniilor
if((a>n-1)|(a<0)|(b>n-1)|(b<0)) printf("\n Interchanging is not posible!");
else
{
for(j=0;j<m;j++) //interschimbarea liniilor
{
var=x[a][j];
x[a][j]=x[b][j];
x[b][j]=var;
}
}
}
i
void interchange_columns(int n,int m,int x[30][30],int a,int b)
{
int i,j,var;
//validarea celor dou pozitii ale coloanelor
if((a>m-1)|(a<0)|(b>m-1)|(b<0)) printf("\n Interchanging is not posible!");
else
{
for(i=0;i<n;i++)// interschimbarea coloanelor
{
var=x[i][a];
x[i][a]=x[i][b];
x[i][b]=var;
}
}
}
Cele dou funcii care urmeaz column_sort i lines_sort au ca parametrii de intrare
dimensiunile matricei i matricea n care se lucreaz. Funciile sorteaz coloanele, respectiv
liniile matricei n funcie de suma elementelor lor. Pentru a face acest lucru funciile apeleaz
funcia care calculeaz sumele dup care se sorteaz, adic columns_sum i lines_sort, i
funcia de interschimbare a dou coloane/linii.
Funciile nu returneaz nici o valoare, ci doar modific valorile elementelor matricei.
Funciile sunt :
void column_sort(int n,int m,int x[30][30])
{
int i,j,h[30],v;
columns_sum(n,m,x,h,&v); //se calculeaz sumele pe coloane
// se sorteaz prin interschimbarea coloanelor ntre ele.
for(j=0;j<m-1;j++)
for(i=j;i<m;i++)
if(h[i]<h[j]) interchange_columns(n,m,x,i,j);
}
void lines_sort(int n,int m,int x[30][30])
{
int i,j,h[30],v;
lines_sum(n,m,x,h,&v);//se calculeaz sumele pe linii
// se sorteaz prin interschimbarea liniilor ntre ele.
for(i=0;i<n-1;i++)
for(j=i;j<n;j++)
if(h[j]<h[i]) interchange_lines(n,m,x,i,j);
}
Urmeaz o serie de funcii care vor avea ca parametrii de intrare : dimensiunile matricei, m i
n, matricea i adresa unei variabile de tip integer numit s. La aceast adresa, funcia scrie suma
anumitor elemente ale matricei, elemente selectate dup o caracteristic.
Aceste funcii sunt :
main_diag_sum care calculeaz suma elementelor din matrice care se afl pe diagonala
principal.
void main_diag_sum(int n,int m,int x[30][30],int *s)
{
int i;
*s=0;
//validare a matricei (trebuie s fie ptratic)
if(n!=m) printf("\n The matrix is not a square!");
else
{
for(i=0;i<n;i++)
*s+=x[i][i]; //suma elementelor de pe diagonala principal
printf("\n The sum is %d",*s);
}
}
sec_diag_sum care calculeaz suma elementelor din matrice care se afl pe diagonala
secundar.
void sec_diag_sum(int n,int m,int x[30][30],int *s)
{
int i,j;
*s=0;
//validare a matricei (trebuie s fie ptratic)
if(n!=m) printf("\n The matrix is not a square!");
else
{
for(i=0;i<n;i++)
for(j=0;j<m;j++)
if((i+j)==(n-1)) *s+=x[i][i]; //suma elementelor de pe diagonala secundar
printf("\n The sum is %d",*s);
}
}
up_main_diag_sum care calculeaz suma elementelor din matrice aflate deasupra diagonalei
principale
void up_main_diag_sum(int n,int m,int x[30][30],int *s)
{
int i,j;
*s=0;
//validare a matricei (trebuie s fie ptratic)
if(n!=m) printf("\n The matrix is not a square!");
else
{
for(i=0;i<n;i++)
for(j=0;j<m;j++)
if(j>i) *s+=x[i][j]; //suma elementelor de deasupra diagonalei principale
printf("\n Above main elements sum is :%d",*s);
}
}
down_main_diag_sum care calculeaz suma elementelor din matrice aflate sub diagonala
principal
void down_main_diag_sum(int n,int m,int x[30][30],int *s)
{
int i,j;
*s=0;
//validare a matricei (trebuie s fie ptratic)
if(n!=m) printf("\n The matrix is not a square!");
else
{
for(i=0;i<n;i++)
for(j=0;j<m;j++)
if(j<i) *s+=x[i][j]; //suma elementelor de sub diagonala principal
printf("\n Under main elements sum is:%d",*s);
}
}
up_sec_diag_sum care calculeaz suma elementelor din matrice aflate deasupra diagonalei
secundare
void up_sec_diag_sum(int n,int m,int x[30][30],int *s)
{
int i,j;
*s=0;
//validare a matricei (trebuie s fie ptratic)
if(n!=m) printf("\n The matrix is not a square !");
else
{
for(i=0;i<n;i++)
for(j=0;j<m;j++)
if((i+j)<(n-1)) *s+=x[i][j];
//suma elementelor de deasupra diagonalei secundar
printf("\n Above secondary elements sum is %d",*s);
}
}
down_sec_diag_sum care calculeaz suma elementelor din matrice aflate sub diagonala
principal
void down_sec_diag_sum(int n,int m,int x[30][30],int *s)
{
int i,j;
*s=0;
//validare a matricei (trebuie s fie ptratic)
if(n!=m) printf("\n The matrix is not a square !");
else
{
for(i=0;i<n;i++)
for(j=0;j<m;j++)
if((i+j)>(n-1)) *s+=x[i][j]; //suma elementelor de sub diagonala secundar
printf("\n Under secondary elements sum is%d",*s);
}
}
elem_sum care calculeaz suma tuturor elementelor din matrice
void elem_sum(int n,int m,int x[30][30],int *s)
{
int i,j;
*s=0;
for(i=0;i<n;i++)
for(j=0;j<m;j++)
*s+=x[i][j];// se calculeaz suma
printf("\n Matrix elements sum is %d",*s);
}
up_with_main_diag_sum care calculeaz suma elementelor din matrice aflate deasupra i pe
diagnala secundar
void up_with_main_diag_sum(int n,int m,int a[30][30],int *s)
{
int i,j;
*s=0;
//validare a matricei (trebuie s fie ptratic)
if(n!=m) printf("\n The matrix is not a square !");
else
{
for(i=0;i<n;i++)
for(j=0;j<m;j++)
if(j>=i) *s+=a[i][j];//se calculeaz suma
printf("\n The main diagonal and above it elements' sum is%d",*s);
}
getch();
}
down_with_main_diag_sum care calculeaz suma elementelor din matrice aflate sub i pe
diagonala principal
void down_with_main_diag_sum(int n,int m,int a[30][30],int *s)
{
int i,j;
*s=0;
//validare a matricei (trebuie s fie ptratic)
if(n!=m) printf("\n The matrix is not a square !");
else
{
for(i=0;i<n;i++)
for(j=0;j<m;j++)
if(j<=i) *s+=a[i][j];//se calculeaz suma
printf("\n The main diagonal and under it elements' sum is %d",*s);
}
getch();
}
down_with_sec_diag_sum care calculeaz suma elementelor din matrice aflate sub i pe
diagonala secundar
void down_with_sec_diag_sum(int n,int m,int a[30][30],int *s)
{
int i,j;
*s=0;
//validare a matricei (trebuie s fie ptratic)
if(n!=m) printf("\n The matrix is not a square !");
else
{
for(i=0;i<n;i++)
for(j=0;j<m;j++)
if((i+j)<=(n-1)) *s+=a[i][j];//se calculeaz suma
printf("\n The secondary diagonal and above it elements' sum is %d",*s);
}
getch();
}
up_with_sec_diag_sum care calculeaz suma elementelor din matrice aflate deasupra i pe
diagonala secundar
void up_with_sec_diag_sum(int n,int m,int a[30][30],int *s)
{
int i,j;
*s=0;
//validare a matricei (trebuie s fie ptratic)
if(n!=m) printf("\n The matrix is not a square !");
else
{
for(i=0;i<n;i++)
for(j=0;j<m;j++)
if((i+j)>=(n-1)) *s+=a[i][j];//se calculeaz suma
printf("\n The secondary diagonal and under it elements' sum is %d",*s);
}
getch();
}
Asemntoare cu funciile prezentate anterior, din punctul de vedere al parametrilor de intrare
sunt i urmtoarele. Singura diferen este aceea c la adresa variabilei de tip integer nu se mai
scrie valoarea unei sume de elemente ale matricei ci, valoarea unui element al matricei, cum ar
fi valoarea minim sau valoarea maxim.
minim care gsete valoarea minim a elementelor matricei
void minim(int n,int m,int x[30][30],int *min)
{
int i,j,i1,j1,a;
*min=x[0][0];//se iniializeaz minimul cu primul element din matrice
for(i=0;i<n;i++)
for(j=0;j<m;j++)
if (*min>x[i][j])//se gsete valoarea minim
{
*min=x[i][j];
i1=i;
j1=j;
}
printf("\n The minimum element is %d and it is on line %d and column%d",*min,j1,i1);
}
maxim care gsete valoarea maxim a elementelor din matrice
void maxim(int n,int m,int x[30][30],int *max)
{
int i,j,i1,j1,a;
*max=x[0][0];//se iniializeaz maximul cu primul element al matricei
for(i=0;i<n;i++)
for(j=0;j<m;j++)
if (*max<x[i][j])// se gsete maximul
{
*max=x[i][j];
i1=i;
j1=j;
}
printf("\n The maximum element is %d and it is on line %d and column %d",*max,j1,i1);
}
max_up_main care gsete valoarea maxim a elementelor matricei aflate deasupra diagonalei
principale
void max_up_main(int n,int m,int x[30][30],int *max)
{
int i,j;
//validare a matricei (trebuie s fie ptratic)
if(n!=m) printf("\n The matrix is not a square !");
else
{
*max=x[0][m-1];
for(i=0;i<n;i++)
for(j=0;j<m;j++)
if (i<j) if(*max<x[i][j]) *max=x[i][j]; //gsirea maximului
printf("\n The maximum element above main is %d",*max);
}
}
min_up_main care gsete valoarea minim a elementelor din matrice aflate deasupra
diagonalei principale
void min_up_main(int n,int m,int x[30][30],int *min)
{
int i,j;
//validare a matricei (trebuie s fie ptratic)
if(n!=m) printf("\n The matrix is not a square !");
else
{
*min=x[0][m-1];
for(i=0;i<n;i++)
for(j=0;j<m;j++)
if (i<j) if(*min>x[i][j]) *min=x[i][j];//se gsete minimul
printf("\n The minimum element above main is %d",*min);
}
}
max_down_main care gsete valoarea maxim a elementelor din matrice aflate sub diagonala
principal
void max_down_main(int n,int m,int x[30][30],int *max)
{
int i,j;
//validare a matricei (trebuie s fie ptratic)
if(n!=m) printf("\n The matrix is not a square !");
else
{
*max=x[n-1][0];
for(i=0;i<n;i++)
for(j=0;j<m;j++)
if (i>j) if(*max<x[i][j]) *max=x[i][j]; //se gsete maximul
printf("\n The maximum element under is %d",*max);
}
}
min_down_main care gsete valoarea minim a elementelor matricei aflate sub diagonala
principal
void min_down_main(int n,int m,int x[30][30],int *min)
{
int i,j;
//validare a matricei (trebuie s fie ptratic)
if(n!=m) printf("\n The matrix is not a square !");
else
{
*min=x[n-1][0];
for(i=0;i<n;i++)
for(j=0;j<m;j++)
if (i>j) if(*min>x[i][j]) *min=x[i][j];//se gsete minimul
printf("\n The minimum element under main is %d",*min);
}
}
max_down_sec care gsete valoarea maxim a elementelor matricei aflate sub diagonala
secundar
void max_down_sec(int n,int m,int x[30][30],int *max)
{
int i,j;
//validare a matricei (trebuie s fie ptratic)
if(n!=m) printf("\n The matrix is not a square !");
else
{
*max=x[n-1][m-1];
for(i=0;i<n;i++)
for(j=0;j<m;j++)
if (i+j>n-1) if(*max<x[i][j]) *max=x[i][j];//se gsete maximul
printf("\n The maximum element under secondary is %d",*max);
}
}
min_down_sec care gsete valoarea minim a elementelor matricei aflate sub diagonala
secundar
void min_down_sec(int n,int m,int x[30][30],int *min)
{
int i,j;
//validare a matricei (trebuie s fie ptratic)
if(n!=m) printf("\n The matrix is not a square !");
else
{
*min=x[n-1][m-1];
for(i=0;i<n;i++)
for(j=0;j<m;j++)
if (i+j>n-1) if(*min>x[i][j]) *min=x[i][j];//se gsete minimul
printf("\n The minimum element under secondary diagonal is %d",*min);
}
}
min_main_diag care gsete valoarea minim a elementelor din matrice aflate pe diagonala
principal
void min_main_diag(int n,int m,int a[30][30],int *min)
{
int i,j;
//validare a matricei (trebuie s fie ptratic)
if (n!=m) printf("The matrix is not a square !");
else
{
*min=a[0][0];
for(i=0;i<n;i++)
if (*min>a[i][i]) *min=a[i][i];//se gsete minimul
printf("\n Main diagonal minimum element is: %d ",*min);
getch();
}
}
max_main_diag care gsete valoarea maxim a elementelor din matrice aflate pe diagonala
principal
void max_main_diag(int n,int m,int a[30][30],int *max)
{
int i,j;
//validare a matricei (trebuie s fie ptratic)
if (n!=m) printf("The matrix is not a square !");
else
{
*max=a[0][0];
for(i=0;i<n;i++)
if (*max<a[i][i]) *max=a[i][i];//se gsete maximul
printf("\n Main diagonal maximum element is %d ",*max);
getch();
}
}
min_sec_diag care gsete valoarea minim a elementelor din matrice aflate pe diagonala
secundar
void min_sec_diag(int n,int m,int a[30][30],int *min)
{
int i,j;
//validare a matricei (trebuie s fie ptratic)
if (n!=m) printf("The matrix is not a square !");
else
{
*min=a[0][n-i-1];
for(i=0;i<n;i++)
if (*min>a[i][n-i-1]) *min=a[i][n-i-1];//se gsete minimul
printf("\n Secondary diagonal minimum element is: %d ",*min);
getch();
}
getch();
}
max_sec_diag care gsete valoarea maxim a elementelor din matrice aflate pe diagonala
secundar
void max_sec_diag(int n,int m,int a[30][30],int *max)
{
int i,j;
//validare a matricei (trebuie s fie ptratic)
if (n!=m) printf("The matrix is not a square !");
else
{
*max=a[0][n-i-1];
for(i=0;i<n;i++)
if (*max<a[i][n-i-1]) *max=a[i][n-i-1];//se gsete maximul
printf("\n Secondary diagonal maximum element is%d ",*max);
getch();
}
}
max_up_sec care gsete valoarea maxim a elementelor din matrice aflate deasupra diagonalei
secundare
void max_up_sec(int n,int m,int a[30][30],int *max)
{
int i,j;
//validare a matricei (trebuie s fie ptratic)
if(n!=m) printf("\n The matrix is not a square !");
else
{
*max=a[0][0];
for(i=0;i<n;i++)
for(j=0;j<m;j++)
if (i+j<n-1)
if(*max<a[i][j]) *max=a[i][j];//se gsete maximul
printf("\n The maximum element above secondary diagonal is %d",*max);
}
}
min_up_sec care gsete valoarea minim a elementelor din matrice aflate deasupra diagonalei
secundare
void min_up_sec(int n,int m,int a[30][30],int *min)
{
int i,j;
//validare a matricei (trebuie s fie ptratic)
if(n!=m) printf("\n The matrix is not a square !");
else
{
*min=a[0][0];
for(i=0;i<n;i++)
for(j=0;j<m;j++)
if (i+j>n-1)
if(*min>a[i][j]) *min=a[i][j];//se gsete minimul
printf("\n The minimum element above secondary diagonal is %d",*min);
}
}
Funciile lines_min, lines_max i columns_min, columns_max vor afla elementele minime
i maxime de pe fiecare linie, respectiv coloan i le vor scrie ntr-un vector. Parametrii de
intrare ale acestor funcii sunt aceiai la toate i anume : n numrul de linii al matricei, m
numrul de coloane al matricei, X[ ][ ] matricea respectiv, h[ ] vectorul n care se scriu
valorile minime sau maxime i adresa unei variabile ntregi la care se scrie valoarea numrului
de elemente ale vectorului.
Astfel funcia lines_min afl minimul elementelor de pe fiecare linie.
void lines_min(int n,int m,int x[30][30],int h[30],int *l)
{
int i,j,min;
for(i=0;i<n;i++)
{
min=x[i][0];
for(j=0;j<m;j++)
if (min>x[i][j]) min=x[i][j];
h[i]=min;//se afl minimul pe linia i
}
*l=n;//se scrie dimensiunea vectorului
}
Funcia columns_min gsete minimul elementelor de pe fiecare coloan
void columns_min(int n,int m,int x[30][30],int h[30],int *l)
{
int i,j,min;
for(j=0;j<m;j++)
{
min=x[0][j];//se iniializeaz minimul
for(i=0;i<n;i++)
if (min>x[i][j]) min=x[i][j];
h[j]=min;//minimul pe coloana j
}
*l=m;//dimensiunea vectorului
}
Funcia columns_max gsete valoarea maxim a elementelor de pe fiecare coloan
void columns_max(int n,int m,int x[30][30],int h[30],int *l)
{
int i,j,max;
for(j=0;j<m;j++)
{
max=x[0][j];
for(i=0;i<n;i++)
if (max<x[i][j]) max=x[i][j];
h[j]=max;//maximul de pe coloana j
}
*l=m; //dimensiunea vectorului
}
Funcia lines_max gsete valoarea maxim a elementelor de pe fiecare linie
void lines_max(int n,int m,int x[30][30],int h[30],int *l)
{
int i,j,max;
for(i=0;i<n;i++)
{
max=x[i][0];
for(j=0;j<m;j++)
if (max<x[i][j]) max=x[i][j];
h[i]=max;//maximul de pe linia i
}
*l=n;//dimensiunea vectorului
}
Funcia repl_neg nlocuiete toate elementele negative ale unei matrice. Pentru a face acest
lucru ea are ca date de intrare doar dimensiunile matricei i matricea, ea nereturnnd vreo
valoare. De asemenea funcia afieaz pe ecran numrul de elemente a cror valoare a fost
modificat.
Funcia nu modific structura matricei sau adresele fizice ale elementelor sale, ci doar
valoarea elementelor.
void repl_neg(int n,int m,int x[30][30])
{
int i,j,count;
count=0;
for(i=0;i<n;i++)
for(j=0;j<m;j++)
if(x[i][j]<0)//se gsete elementele negative
{
x[i][j]=0;//se nlocuiesc cu valoarea 0
count++;//se numr cte au fost nlocuite
}
printf("\n %d elements have been replaced with 0",count);
}
Urmtoarele dou funcii delete_line i delete_column modific structura unei matrice, n
sensul ca terg o linie/coloan din matrice modificnd astfel dimensiunea matricei. Pentru a
memora noua dimensiune a matricei, pe lng parametrii obinuii de intrare (n, m i X) funciile
mai au ca parametru i adresa unei variabile de tip ntreg unde se scrie valoarea noului numr de
linii sau coloane. Folosind acest pointer la ntreg ca parametru de intrare tipul funciilor este
void.
Ambele funcii primesc poziia liniei/coloanei de ters din matrice n interiorul lor, ele cernd
acest lucru utilizatorului.
Prima funcie care realizeaz tergerea unei linii este :
void delete_line(int n,int m,int x[30][30],int *n1)
{
int i,j,l,k;
//se cere linia care va fi ters
printf("\n Line to be deleted (between 0 and %d):",n-1);
k=scanf("%d",&l);
/*tergerea se realizeaz prin interschimbarea liniilor ntre ele, pn cnd linia care se terge
va ajunge ultima */
for(i=l;i<n-1;i++)
interchange_lines(n,m,x,i,i+1);
//se modific numrul de linii, i astfel linia se terge logic ea existnd n matricea iniial pe
ultima poziie dar ne mai fiind citit
*n1=n-1;
}
A doua funcie care terge o coloan este :
void delete_column(int n,int m,int x[30][30],int *m1)
{
int i,j,c,k;
//se cere coloana care va fi tears
printf("\n Column to be deleted (between 0 and %d):",m-1);
k=scanf("%d",&c);
/*tergerea se realizeaz prin interschimbarea coloanelor ntre ele, pn cnd coloana care
se terge va ajunge ultima */
for(j=c;j<m-1;j++)
interchange_columns(n,m,x,j,j+1);
/*se modific numrul de coloane, i astfel coloana se terge logic ea existnd n matricea
iniial pe ultima poziie dar ne mai fiind citit*/
*m1=m-1;
}
Funcia how_many_0 primind ca date de intrare dimensiunile unei matrice, matricea i adresa
unei variabile de tip ntreg scrie la aceast adres numrul de elemente din matrice care au
valoarea 0.
void how_many_0(int n,int m,int x[30][30],int *no)
{
int i,j;
*no=0;
for(i=0;i<n;i++)
for(j=0;j<m;j++)
//se gsesc elementele egale cu 0 i se numr
if(x[i][j]==0) (*no)++;
*no=((*no*100)/(n*m));
//se afieaz procentul lor n numrul total de elemente ale matricei
printf("\n Elements with value 0 are %d per cent of all elements",*no);
}
Funcia care urmeaz modific structura unei matrice n sensul c adaug o nou linie la
matrice. Pentru a face acest lucru ea are ca parametrii de intrare numrul de linii al matricei, n,
numrul de coloane, m, matricea i doi pointeri la ntregi. La cele dou adrese de variabile de
tip ntreg se scriu noile valori ale dimensiunilor matricei. La adreasa lui n1 se scrie noul numr
de linii, iar la adresa lui m1 se scrie noul numr de coloane. Funcia odat apelat cere
utilizatorului s introduc elementele noii linii. Noua linie va avea m elemente.
void add_line(int n,int m,int x[30][30],int *n1,int *m1)
{
int i,j,h[30],k;
/* cum matricea este definit static cu un numr maxim de 30 de linii, se verific dac se mai
pot aduga noi linii*/
if(n==30) printf("\n No more lines to add!");
else
{
//se introduc elementele noii linii
printf("\n The new line is:");
for(j=0;j<m;j++)
{
printf("\n The element h[%d] is:",j);
k=scanf("%d",&h[j]);
valid_no_integer(&h[j],k);
}
//se adaug noua linie
for(j=0;j<m;j++)
x[n][j]=h[j];
*n1=n+1;//noul numr de linii al matricei
*m1=m;//noul numr de coloane al matricei
}
}
Urmtoarea serie de funcii primesc ca parametrii de intrare dimensiunile matricei (n i m) i
matricea A i returneaz diferite valori calculate pe baza valorilor elementelor matricei.
Funcia pos_elem_geom_avr returneaz o valoare de tip float calculat ca medie geometric a
elementelor pozitive ale matricei
float pos_elem_geom_avr(int n,int m,int a[30][30])
{
int i;int j;
float avr=1.;int k=0;
for(i=0;i<n;i++)
for(j=0;j<m;j++)
if(a[i][j]>0)
{
//se calculeaz produsul elementelor pozitive
avr*=a[i][j];
k++;
}
//dac sunt elemente pozitive n matrice se calculeaz media geometric ca fiind radical de
ordinul k din produsul valorilor elementelor pozitive//
if(k>1) avr=exp(log(avr)/k);
else avr=-1;//dac nu sunt elemente pozitive atunci funcia returneaz -1
return avr;
}
Funcia prime_elem_no returneaz un ntreg ce reprezint numrul de elemente prime din
matrice
int prime_elem_no(int n,int m,int a[30][30])
{
int i;int j;
int sum=0;
for(i=0;i<n;i++)
for(j=0;j<m;j++)
/* pentru a vedea dac un numr este prim se folosete funcia prim care se afl n
bibliotec*/
if (prim(a[i][j])) sum++;
return sum;
}
Funcia pos_elem_sum returneaz un ntreg care reprezint suma elementelor pozitive
int pos_elem_sum(int n,int m,int a[30][30])
{
int i;int j;
int sum=0.;
for(i=0;i<n;i++)
for(j=0;j<m;j++)
if(a[i][j]>0) sum+=a[i][j];
return sum;
}
Funcia pos_elem_no returneaz un ntreg ce reprezint numrul de elemente pozitive
int pos_elem_no(int n, int m,int a[30][30])
{
int i;int j;
int no=0.;
for(i=0;i<n;i++)
for(j=0;j<m;j++)
if(a[i][j]>0) no++;
return no;
}
Funcia zero_elem_no returneaz un ntreg ce reprezint numrul de elemente ale matricei egale
cu 0
int zero_elem_no(int n, int m, int a[30][30])
{
int i;int j;
int no=0.;
for(i=0;i<n;i++)
for(j=0;j<m;j++)
if(a[i][j]==0) no++;
return no;
Funcia neg_elem_no returneaz un ntreg care reprezint numrul de elemente negative din
matrice
int neg_elem_no(int n, int m, int a[30][30])
{
int i;int j;
int no=0.;
for(i=0;i<n;i++)
for(j=0;j<m;j++)
if(a[i][j]<0) no++;
return no;
}
Funcia neg_elem_sum returneaz un ntreg care reprezint suma elementelor negative din
matrice
int neg_elem_sum(int n,int m,int a[30][30])
{
int i;int j;
int sum=0.;
for(i=0;i<n;i++)
for(j=0;j<m;j++)
if(a[i][j]<0) sum+=a[i][j];
return sum;
}
Funcia even_elem_no returneaz un ntreg care reprezint numrul de elemente impare din
matrice
int even_elem_no(int n, int m,int a[30][30])
{
int i;int j;
int no=0.;
for(i=0;i<n;i++)
for(j=0;j<m;j++)
if(!(a[i][j] %2)) no++;
return no;
}
Funcia odd_elem_no returneaz un ntreg care reprezint numrul de elemente pare din matrice
int odd_elem_no(int n, int m, int a[30][30])
{
int i;int j;
int no=0.;
for(i=0;i<n;i++)
for(j=0;j<m;j++)
if(a[i][j] % 2) no++;
return no;
}
Funcia sum_module returneaz un ntreg ce reprezint suma valorilor n modul ale elementelor
matricei
int sum_module(int n,int m,int x[30][30])
{
int i,j,sum;
sum=0;
for(i=0;i<n;i++)
for(j=0;j<m;j++)
if(x[i][j]<0) sum-=x[i][j];
//dac numrul este negativ se face modul din valoarea sa
else sum+=x[i][j];
return sum;
}
Funcia abs_lines_max_sum returneaz un ntreg ce reprezint suma valorilor n modul ale
maximelor de pe linii
int abs_lines_max_sum(int n,int m,int x[30][30])
{
int i,l,h[30],sum;
sum=0;
//se folosete funcia lines_max care scrie ntr-un vector maximele de pe linii
lines_max(n,m,x,h,&l);
for(i=0;i<l;i++) if(h[i]<0) sum-=h[i];
else sum+=h[i];
return sum;
}
Funcia abs_columns_max_sum returneaz un ntreg care reprezint suma valorilor n modul a
maximelor de pe coloane
int abs_columns_max_sum(int n,int m,int x[30][30])
{
int i,l,h[30],sum;
sum=0;
//se folosete funcia columns_max care scrie ntr-un vector maximele de pe linii
columns_max(n,m,x,h,&l);
for(i=0;i<l;i++) if(h[i]<0) sum-=h[i];
else sum+=h[i];
return sum;
}
Funcia max_on_one_linie primete ca date de intrare numrul de linii al matricei, n, numrul
de coloane al matricei, m, matricea definit static, X, un ntreg numit l care reprezint linia pe
care se lucreaz i un pointer la o variabil de tip integer, *r. Funcia caut pe linia l valoarea
maxim i la adresa variabilei r scrie numrul coloanei pe care se afl valoarea maxim a liniei
respective. De asemenea funcia returneaz maximul.
int max_on_one_linie(int n,int m,int x[30][30],int l,int *r)
{
int j,max;
//se verifica dac linia exist
if ((l>30)|(l<0)|(l>n-1))
{
printf("\n Error, this line does not exist!");
getch();
exit(0);
}
for(j=0;j<m;j++)
//se caut maximul pe linia l
if (max<x[l][j])
{
max=x[l][j];
*r=j;//j este coloana pe care se afl maximul
}
return max;
}
Funcia max_on_one_column este asemntoare cu cea precedent, numai c ea caut
maximul pe o coloan i la adresa variabilei l se scrie linia pe care se afl maximul din acea
coloan
int max_on_one_column(int n,int m,int x[30][30],int c,int *l)
{
int i,max;
//se verific dac coloana exist
if ((c>30)|(c<0)|(c>m-1))
{
printf("\n Error, this column doesn't exist !");
getch();
exit(1);
}
for(i=0;i<n;i++)
//se caut maximul pe coloana c
if (max<x[i][c])
{
max=x[i][c];
*l=i;//i este linia pe care se afl maximul
}
return max;
}
Funcia lines_max_position returneaz un vector care conine numrul coloanei pe care se
afl elementele maxime de pe fiecare linie. Parametrii funciei sunt : n numrul de linii al
matricei, m numrul de coloane al matricei, X matricea definit static, vectorul definit static n
care se trec coloanele i un pointer la ntreg unde se scrie dimensiunea vectorului.
void lines_max_position(int n,int m,int x[30][30],int v[30],int *l)
{
int i,j,max;
for(i=0;i<n;i++)
{
max=x[i][0];//se iniializeaz maximul pentru fiecare linie
v[i]=0;
for(j=0;j<m;j++)
if (max<x[i][j])
{
v[i]=j;//odat maximul gsit se memoreaz i coloana pe care se afl
max=x[i][j];
}
}
*l=n; //se memoreaz dimensiunea vectorului
}
Funcia max_on_diag pune pe diagonala principal a unei matrice ptratice maximele de pe
fiecare linie cu ajutorul operaiilor de interschimbare a liniilor sau coloanelor. Parametrii
funciei sunt : n numrul de linii al matricei, m numrul de coloane al matricei i X matricea
definit static. Funcia nu face acest lucru atunci cnd maximele a dou sau mai multe linii se
afl pe aceeai coloan pentru c doar cu operaiile de interschimbare aceste maxime nu se pun
pe diagonal.
void max_on_diag(int n,int m, int x[30][30])
{
int i,j,no,v[30],l,k;
int vb=1;
//se verific dac matricea este ptratic
if(n!=m)
{
printf("\n Error ! The matrix must be a square ");
getch();
exit(0);
}
/*cu ajutorul funciei lines_max_position definit anterior se trec ntr-un vector maximele de
pe fiecare linie*/
lines_max_position(n,m,x,v,&l);
//se verific n vectorul creat anterior dac dou maxime sunt pe aceeai coloan
for(i=0;i<l-1;i++)
for(j=i+1;j<l;j++)
if(v[i]==v[j]) vb=0;
if(vb==0)
{
printf("\n Eroare ! Two lines have maximum elements on same column");
getch();
exit(0);
}
/*se fac interschimarile de linii i coloane pentru a pune maximele pe diagonala principal */
for(i=0;i<l;i++)
{
interchange_columns(n,m,x,v[i],i);
lines_max_position(n,m,x,v,&k);
}
}
Funcia operation primete pe lng dimensiunile matricei (n i m) i matricea respectiv, 3
ntregi reprezentnd numerele a 3 linii i un caracter ce este unul din operatorii matematici +, -,
*. Dac cei trei ntregi sunt k, i, j atunci funcia calculeaz elementele liniei k ca
sum/diferen/produs dintre elementele liniilor i i j dup formula a[k][r]=a[i][r] operator
a[j][r]
void operation(int n,int m,int x[30][30],int k,int i,int j,char oper)
{
int z;
//se valideaz numerele liniilor
if ((i>30)|(i<0)|(i>n-1)|(j>30)|(j<0)|(j>n-1)|(k>30)|(k<0)|(k>n-1))
{
printf("\n Error ! One of this lines doesn't exist ! ");
getch();
exit(1);
}
//n funcie de opeartor se creaz noua linie
switch(oper)
{
case '+':{ // sum
for(z=0;z<m;z++) x[k][z]=x[i][z]+x[j][z];
break;
}
case '-':{ // diferen
for(z=0;z<m;z++) x[k][z]=x[i][z]-x[j][z];
break;
}
case '*':{//produs
for(z=0;z<m;z++) x[k][z]=x[i][z]*x[j][z];
break;
}
default :{
printf("\n Chose a operator !");
break;
}
}
}
Funciile change_line i change_column modific elementele liniei/coloanei primit ca
parametru de intrare cu o valoare dorit. Valoarea este primit ca dat de intrare.
Funciile sunt :
void change_line(int n,int m,int x[30][30],int line,int value)
{
int k;
for(k=0;k<m;k++) x[line][k]=value;
}
i
void change_column(int n,int m,int x[30][30],int column,int value)
{
int k;
for(k=0;k<n;k++) x[k][column]=value;
}
Funcia balance_sum calculeaz elementele linie line, dat ca parametru, ca sum de
elementele a altor linii care formeaz la rndul lor o list de parametrii reprezentat prin .
Primul parametru a funciei este matricea n care se lucreaz i dimensiunile ei (n i m).
Dac funcia are urmtorul apel balance_sum(a, n, m, n-1,256,-1) atunci elementele liniei n-
1 vor fi egale cu suma elementelor tututor liniilor din matrice. Valoarea 1 indic funciei cnd
se termin lista de parametrii.
Dac funcia are urmtorul apel balance_sum(a, n, m, n-1,2,3,-1) atunci elementele liniei n-1
vor fi egale cu suma elementelor liniilor 2 i 3 din matrice. Valoarea 1 indic funciei cnd se
termin lista de parametrii.
void balance_sum(int a[30][30],int n,int m,int line,...)
{
int k=line,i,j;
//int b[30][30];
va_list lista;
change_line(n,m,a,line,0);
va_start(lista,line);
k=va_arg(lista, int);
while(k!=-1)
{
if(k==256){
j=0;
while(j!=m)
{
//a[line][j]=0;
for(i=0;i<n;i++) if(i!=line) a[line][j]+=a[i][j];
j++;
}
k=va_arg(lista, int);
}
else
{
for (j=0;j<m;j++) a[line][j]+=a[k][j];
k=va_arg(lista,int);
}
}
va_end(lista);
}
Funciile prezentate n acest capitol aparin bibliotecii de funcii matrice.h , ele fiind prezente
i n clasa matrix ns sunt modificate listele de parametrii pentru a putea facilita lucrul cu
obiecte de tip matrix.
5. Matrice rare
Matricele rare i gsesc aplicabilitatea n modelarea unor procese de natur
industrial, economic, tehnic, social etc. Materialul de fa i propune s trateze
modalitile de reprezentare n structuri de date a matricelor rare, precum i principalele
operaii matriceale implementate ntr-un limbaj orientat pe obiecte. n final este
prezentat o aplicaie concret estimarea parametrilor unei regresii statistice.
1. Introducere
n rezolvarea multor probleme de natur economic, tehnic, social, a diverselor
probleme de optimizare, precum i n modelarea unor procese industriale i tehnologice este
necesar s se determine modelul matematic care descrie funcionarea procesului respectiv.
Descrierea acestor sisteme fizice conduce la obinerea unor modele matematice care fie n mod
direct, prin modelare, fie prin metoda de rezolvare implic sisteme de ecuaii algebrice liniare
sau probleme de programare liniar a cror matrice a coeficienilor este rar ( sparse ), n sensul
c ponderea elementelor nenule n totalul elementelor matricei este mic.
Din punct de vedere practic trebuie remarcat faptul c analiza sistemelor mai sus
amintite conduce la obinerea unor modele matematice de mari dimensiuni care implic sisteme
de ecuaii algebrice liniare de mii de ecuaii, pentru a cror rezolvare sunt necesare resurse mari
de memorie i timp de calcul. n multe cazuri practice, cum ar fi sistemele n timp real, timpul
de calcul este o resurs critic, creia nu-I este permis s depeasc o valoare limit.
Modelele matematice ale proceselor reale implic un numr foarte mare de variabile i
restricii care prezint fenomenul de raritate ( sparsity ), adic de slab interconectare a
elementelor sale. Luarea n consideraie a fenomenului de raritate furnizeaz un nou mod de
abordare foarte eficient, ce implic n dezvoltarea aplicaiilor informatice folosirea unor structuri
de date speciale, care s conduc la reducerea resurselor de memorie i a timpului de calcul.
n general, o matrice
) , ( n n
- dimensional este rar dac conine un numr mic de
elemente nenule

, adic
2
n <<
. Cantitativ, matricele rare sunt caracterizate de ponderea
numrului de elemente nenule n totalul de elemente, pondere ce definete gradul de umplere al
matricei. n aplicaiile curente se ntlnesc matrice rare cu grade de umplere ntre 0,15% i 3%.
2. Memorarea matricelor rare.
Se consider matricea:

,
_

0 0 0 1 0
0 0 0 0 0
4 0 2 0 0
0 0 0 0 1
A
Matricea A este un exemplu de matrice rar, ea coninnd 16 elemente nule din totalul
de 20.
Se definete gradul de umplere (densitatea) unei matrice prin raportul dintre numrul
elementelor nenule i numrul total al elementelor sale:
100 (%)

m n
p
G
(1)
unde: p numrul de elemente nenule;
n numrul de linii;
m numrul de coloane.
Se accept, n general, c o matrice este rar dac densitatea sa este de cel mult 3%. Densitatea
matricei A este
% 20 ) ( A G
, ea fiind prezentat aici n scopul ilustrrii conceptului de
matrice rar.
Structura de date clasic folosit pentru manipularea matricelor obinuite tablou de
dimensiune ( n, m ) alocat la compilare se dovedete a fi ineficient n cazul n care ,matricea
este rar. Un prim avantaj este legat de folosirea neeconomic a spaiului de memorie prin
alocarea de zone mari pentru memorarea elementelor nule, care nu sunt purttoare de
informaie. Ocuparea unor zone de memorie cu elemente nule nu se justific deoarece acestea
nu contribuie la formarea rezultatului operaiilor cu matrice (adunare, nmulire, etc) ducnd
totodat i la mrirea duratei de realizare a acestor operaii prin ocuparea procesorului cu
adunri i nmuliri scalare cu zero. Acest inconvenient se manifest cu att mai pregnant cu ct
dimensiunea matricei este mai mare.
Prin urmare, pentru probleme de dimensiuni mari, s-a cutat gsirea unor modaliti de
reprezentare compact a matricelor rare, n care s se renune la memorarea elementelor nule. n
acest caz este necesar ca tehnicile de memorare s ncorporeze e lng elementele nenule i
mijloacele de identificare a poziiilor acestor elemente n matrice.
Sunt prezentate n continuare cteva posibiliti de memorare compact a MR. Se face
de asemeni o analiz a oportunitii folosirii fiecrei tehnici n parte, n funcie de densitatea
matricei.
Memorarea prin identificare binar se bazeaz pe natura binar a sistemului de calcul,
constnd n memorarea numai a elementelor nenule ale matricei ntr-o zon primar ZP avnd
tipul de baz corespunztor tipului elementelor matricei i dimensiunea egal cu numrul
elementelor nenule.
Structura matricei este indicat printr-o secven binar memorat ntr-o zon secundar ZS.
Matricea A prezentat anterior se memoreaz astfel:
Zona primar
Locaie 1 2 3 4
Valoare 1 -2 4 -1
Zona secundar
Locaie 1 5 6 10
Valoare 1 0 0 0 0 0 0 1 0 1
Locaie 11 15 16 20
Valoare 0 0 0 0 0 0 1
Matricea A a fost memorat n ordinea liniilor, dar se poate imagina o alt posibilitate
de memorare, n ordinea coloanelor. Zona secundar prezentat mai sus poate fi memorat chiar
la nivel de bit.
Dac matricea B ( m, n ) dimensional are densitatea G i dac tipul de baz al
matricei (tipul fiecruia dintre elemente nenule ale matricei) este reprezentat printr-un cuvnt de
b octei, atunci zona primar va necesita mnG cuvinte de b octei iar zona secundar mn/8b
cuvinte. Numrul total de cuvinte necesare memorrii matricei B prin intermediul celor dou
zone este mnG + mn/8b. ntruct pentru memorarea matricei n forma clasic sunt necesare mn
cuvinte, raportul dintre cerinele de memorie ale structurii de mai sus i a celei standard este:
8 1
1
b G c / +
(2)
n relaia (2) s-a considerat c memorarea zonei secundare se face la nivel de bit.
Considernd c elementele matricei A sunt reale i se reprezint pe 4 octei, rezult:
23 , 0 32 / 1 2 , 0
1
+
A
c
adic memorarea matricei A conform acestei structuri ocup de circa 4 ori mai puin memorie
dect cea standard.
Folosind relaia (2) n care se egaleaz
1
1
c
se determin limita superioar a
densitii unei matrice pentru care aceast structur necesit mai puin memorie dect cea
standard:
8 1 1 b G /
lim

(3)
Pentru matricea A:
% 96 96 , 0 32 / 1 1
lim
G
Aceast structur de memorare difer de altele prin aceea c n zona secundar este
alocat memorie i pentru elementele nule ale matricei (un singur bit). Structura este mai puin
eficient pentru matricele de mari dimensiuni foarte rare. Principala dificultate const n
complexitatea programelor de implementare a operaiilor matriciale.
O alt modalitate de memorare prin identificare binar se obine prin modificarea
informaiilor din zona secundar. Aceast zon va conine pe jumti de cuvnt indicii de
coloan ai elementelor nenule din matrice, precum i anumite informaii de control pentru
identificarea rapid a poziiei elementelor nenule n matrice. Structura ZS pe cuvinte este
urmtoarea:
Numrul
cuvntului
Jumtatea stng Jumtatea dreapt
1 Numrul de linii Numrul de coloane
2 Numrul de elemente nenule
3 Numrul de elemente nenule n
linia1
Numrul de elemente nenule n
linia 2
4 Numrul de elemente nenule n
linia 3
etc

k Numrul de elemente nenule n
ultima linie
k + 1 Indicele de coloan al primului
element memorat
Indicele de coloan al celui de-al
doilea element memorat
k + 2 Indicele de coloan al celui de-al
treilea element memorat
etc.

j Indicele de coloan al ultimului
element memorat
Pentru matricea A, ZS are urmtoarea structur:
Locaie 1 2 3 4 5 6
Valoare 4 5 4 1 2 0 1 1 3 5 2
n reprezentarea de mai sus s-a considerat c elementele nenule sunt reprezentate pe 4
octei astfel c o jumtate de cuvnt n zona secundar se reprezint pe 2 octei. Prin structura de
memorare prezentat mai sus se pot memora matrice a cror dimensiune maxim este de 9999
de linii sau coloane cu numrul de elemente nenule memorate de 10
8
1. Se face observaia c
n cazul matricelor ptrate n primul cuvnt din ZS se va memora dimensiunea matricei.
Numrul total de cuvinte necesare zonei secundare va fi
2 / ) 5 ( mnG m+ +
rotunjit
la cel mai mare ntreg. Numrul total de cuvinte necesar memorrii unei matrice prin
intermediul celor dou zone ZP i ZS este
2 / ) 3 5 ( mnG m+ +
.
Raportul dintre cerinele de memorie ale acestei structuri de identificare binar i a
celei standard este:

2
5
2
3
2
mn
m G
c
+
+
(4)
Pentru o matrice ptrat (m = n), egalnd c2 = 1 n (4) i trecnd la limit pentru
m
rezult valoarea maxim a densitii unei matrice rare pentru care structura prezentat
este eficient:
6 66 666 0
2
5
1
3
2
2
% , ,
lim

,
_


m
m
G
m
(5)
n relaia (5) se ajunge la acelai rezultat n cazul unei matrice neptratice pentru care
se trece la limit pentru
n
i
m
.
Pentru o matrice rar (100,100) dimensional cu o medie de 66 elemente nenule pe
linie, structura de mai sus necesit un total de 6600 + ( 5 + 100 + 6600 )/2 = 9952 cuvinte, cu
ceva mai puin (0,6%) de 10.000 cuvinte necesare pentru memorarea standard. ntruct
densitatea elementelor nenule ale unei matrice rare este de obicei ntre 1% i 3%. Structura se
dovedete a fi deosebit de eficient.
Memorarea compact aleatoare const n utilizarea unei zone primare ZP, coninnd
numai elementele nenule ale matricei i a dou zone secundare coninnd indicii de linie i de
coloan corespunztoare elementelor nenule.
Deoarece fiecare element nenul al matricei este identificat individual, este posibil ca
matricea s fie memorat n ordine aleatoare. Matricea A se memoreaz astfel:
Locaia 1 2 3 4
Valoare 1 -2 4 -1
Indice linie 1 2 2 4
Indice coloan 1 3 5 2
Avantajele memorrii compacte aleatoare constau n faptul c noi elemente nenule ale
matricei pot fi adugate la sfritul zonelor de memorare fr a perturba celelalte elemente,
precum i o manevrabilitate rapid a datelor. n cazul matricelor simetrice aceast structur de
memorare se poate simplifica prin memorarea numai a elementelor nenule de deasupra
diagonalei principale, precum i a elementelor nenule situate pe aceast diagonal.
Numrul total de cuvinte necesare memorrii unei matrice ( m,n ) dimensionale este
n acest caz 3mn. Raportul dintre cerinele de memorie ale acestei structuri i a celei standard
este:
3
3
G c
(6)
Egalnd relaia (6) cu unitatea se determin valoarea limit a densitii matricei pentru rare
aceast structur este eficient:
% 3 , 33
lim
G
.
n structura de mai sus pentru identificarea elementelor nenule ale matricei rare au fost
folosite dou zone secundare corespunztoare indicelui de linie i de coloan. Se prezint n
continuare o alt posibilitate de memorare n care se va utiliza o singur zon secundar de
dimensiune egal cu numrul de elemente nenule ale matricei, coninnd simultan informaii
asupra indicilor de linie i de coloan.
Astfel, fiecrui element din zona primar i se ataeaz n zona secundar un numr
ntreg din care se pot determina indicii de linie i de coloan. Dac elementul
0
ij
a
este
memorat n locaia k a zonei primare atunci n zona secundar se va memora numrul
n j i ) 1 ( +
, unde n este numrul de coloane a matricei. Acest numr, singur, este suficient
pentru identificarea elementului n matrice.
Utiliznd acest artificiu, matricea A se memoreaz astfel:
Locaia 1 2 3 4
Valoare 1 -2 4 -1
Indice agregat 1 12 22 9
Pentru a regsi indicele de linie i de coloan al oricrui element memorat n locaia k
se utilizeaz urmtoarea tehnic de calcul:
- coloana j este obinut ca:
j este mai mic ntreg

Indice agregat (k)/n,


- linia i este determinat astfel:
i = Indice agregat (k) ( j 1 ) n.
Avantajul acestei structuri de memorare const n faptul c necesit mai puin
memorie dect cea precedent, fiind n schimb mai puin rapid n ce privete manevrarea
datelor.
Numrul total de cuvinte necesar memorrii matricei este 2mnG. Raportul dintre
cerinele de memorie ale acestei structuri i a celei standard este
G c 2
4

(7)
Valoarea limit a densitii matricei pentru care aceast structur este eficient este: G
= 50%.
Memorarea compact sistematic presupune c elementele nenule ale unei matrice rare
sunt memorate ntr-o anumit ordine (pe linii sau pe coloane). n acest caz nu este necesar s se
memoreze n zonele secundare indicii de linie, respectiv de coloan. Pentru o memorare n
ordinea liniilor, ne putwem dispersa de indicii de linie, ns se cere specificarea nceputului
fiecrei linii.
i n acest caz se pot imagina mai multe structuri de memorare. Cea prezentat n
continuare este caracterizat prin faptul c utilizeaz o singur zon secundar ZS, care conine
indicii de coloan ale elementelor nenule din matricea considerat, precum i elemente false
care indic nceputul fiecrei linii i sfritul memorrii ntregii matrice. De exemplu, un
element zero n ZS marcheaz prezena unui element fals i acesta specific n ZP numrul liniei
elementelor de la dreapta locaiei. Sfritul matricei este marcat prin prezena n ZP a unui
element fals cu valoarea zero.
Pentru matricea A, memorarea n acest form este urmtoarea:
Locaia 1 2 3 4 5 6 7 8
ZP 1 1 2 -2 4 4 -1 0
ZS 0 1 0 3 5 0 2 0
Pentru aceast structur de memorare numrul maxim de cuvinte necesar pentru a
memora o matrice rar ( m, n ) dimensional este
) 1 ( 2 + + m mnr
. Raportul de memorare
este:
1 2 2
5
) ( / ) ( mm m G c + +
(8)
Se constat c structura este eficient pentru memorarea matricelor rare cu o densitate a
elementelor nenule de maximum 50%.
Memorarea cu ajutorul listelor reprezint o extensie a memorrii compacte aleatoare.
n timpul operaiilor de inversare a matricelor rare noi elemente nenule sunt continuu generate
iar altele sunt anulate i deci structurile de memorare trebuie s fie capabile s execute aceste
modificri ntr-un mod eficient. De aceea structurile de memorare bazate pe aceast tehnic sunt
folosite pentru memorarea i manipularea matricelor rare de mari dimensiuni.
Structura propus utilizeaz o zon principal ZP pentru memorarea elementelor
nenule i trei zone secundare, astfel: ZSL pentru memorarea indicilor de linie ai elementelor
nenule, ZSC pentru indicii de coloan i ZSU pentru memorarea adresei urmtorului element
al matricei. Matricea A se memoreaz dup cum urmeaz:
Locaia 1 2 3 4
ZP 1 -2 4 -1
ZSL 1 2 2 4
ZSC 1 3 5 2
ZSU &2 &3 &4 NULL
unde prin &2 se nelege adresa celei de-a doua locaii.
Raportul dintre cerinele de memorare ale acestei structuri i a celei standard este:
4
6
G c
(9)
Prin urmare aceast structur de memorare este eficient pentru memorarea matricelor
cu o densitate a elementelor nenule de maximum 25%.
3. Software orientat spre lucrul cu matrice rare
Metodele de calcul cu matrice rar pentru a fi eficiente trebuie s beneficieze de
proporia mare de elemente nule din aceste matrice, ceea ce creeaz necesitatea considerrii
unor tehnici speciale de memorare, programare i analiz numeric.
O cerin esenial n programarea matricelor rare const n memorarea i executarea
operaiilor numerice numai cu elementele nenule ale matricei, de a salva memorie i timp de
calcul. n acest caz memorarea standard, devenind ineficient, este abandonat i nlocuit cu
metode de memorare adecvate, cteva dintre acestea fiind prezentate n paragraful anterior.
Un program de calcul cu matrice rare este cu att mai eficient cu ct timpul de calcul i
cerinele de memorie necesare sunt mai reduse fa de acelea ale unui program readiional. De
aceea tehnica de programare trebuie s realizeze o proporie convenabil ntre timpul de calcul
i memoria utilizat, cerine care de cele mai multe ori sunt contradictorii. n general, este
recunoscut necesitatea unei anumite de structuri de memorare a datelor i o anumit tehnic de
manipulare a acestora n cadrul unui algoritm n care sunt implicate matricele rare. Principiul
fundamental de programare cu matrice rare const n memorarea i manipularea numai a
elementelor nenule, de sortare i ordonare n structuri speciale n vederea meninerii structurii
de matrice rar i a stabilitii numerice, de evitare a buclelor complete.
n scopul ilustrrii principalelor operaii efectuate asupra matricelor rare s-a fcut
implementarea acestora n limbajul VisualC++. Pentru reprezentarea matricelor s-a ales
memorarea compact aleatoare, datorit flexibilitii n manevrarea datelor. Este prezentat n
continuare o parte a clasei MR, coninnd constructorii, destructorul, cteva dintre funciile i
operatorii implementai i seciunea privat.
};
e; * tip
l; * int
c; * int
n; int
dim; long
label; int
: private
); ( MR ~ virtual
); ( MR
int); int, (int, MR
(float); * operator & MR
x); & (MR * operator & MR
x); & (MR - operator & MR
x); & (MR operator & MR
); ( ! operator & MR
(int); I & MR
*); char (const Read void
); ( Write void
); * char (const FileWrite void
); ( Insert void
); ( Delete void
); ( Change void
); ( Find long
&); (int Full * tip
) ( Tras float
float); (int, Generate void
(float); Zero void
(float); One void
. . .
public
{
classMr
+
n cadrul seciunii private, label reprezint o etichet ce servete pentru identificarea
matricei, n este dimensiunea matricei, dim servete pentru memorarea numrului de elemente
nenule, l i c sunt pointeri la masive de ntregi reprezentnd linia, respectiv coloana elementelor
nenule, iar e este pointer la un masiv avnd tipul de baz tip (tipul de baz al elementelor
matricei).
Softul realizat vizeaz principalele operaii necesare manipulrii matricelor rare:
construirea acestora (prin introducerea datelor de la tastatur), vizualizarea lor, scrierea i citirea
din fiiere, principalele operaii matriceale: adunarea, scderea, transpunerea, nmulirea i
inversarea.
Pe parcursul dezvoltrii clasei MR s-a dovedit necesar implementarea unei funcii (
void Zero (float) ) care s elimine dintr-o matrice acele elemente care sunt foarte mici (cu cteva
ordine de mrime mai mici dect restul elementelor). Aceste elemente cu valoare
nesemnificativ sunt rezultatul erorilor sistematice introduse prin rotunjiri, datorate numrului
finit de octei n care se face reprezentarea diverselor tipuri de date n calculator. S-a realizat de
asemeni o funcie (Generate(float)) care s construiasc o matrice rar cu elemente aleatoare,
avnd impus n schimb valoarea gradului de umplere.
n continuare se face o prezentare detaliat a operatorilor care implementeaz
principalele operaii matriceale: adunarea, scderea, transpunerea, nmulirea i inversarea.
4. Adunarea, scderea i transpunerea
Adunarea matricelor rare presupune parcurgerea ctorva pai:
determinarea numrului de elemente nenule ale matricei sum;
alocarea memoriei corespunztoare acestui numr;
determinarea acelor elemente din prima matrice care nu au corespondent n
cea de-a doua i adugarea lor la matricea sum;
determinarea elementelor din cea de-a doua matrice care nu au corespondent
n prima i adugarea lor la matricea sum;
determinarea elementelor comune celor dou matrice, nsumarea lor i
adugarea la matricea sum.
Prin elemente comune au fost desemnate acele elemente caracterizate prin indicii de
linie i de coloan care sunt nenule n ambele matrice.
Pentru implementare s-a folosit suprascrierea operatorilor, pentru a conferi o mai mare
putere de sugestie operaiilor matriceale implementate. Este prezentat n continuare operatorul
care implementeaz operaia de adunare, structurat conform pailor prezentai mai sus. Funcia
Found ( ) este definit n afara clasei MR i servete pentru gsirea elementelor comune celor
dou matrice.
dim; this- D
-; - D
c)) this 1, this- x.c[i], x.1[i], ( (Found if
) i x.dim; i 0; (i for
x.dim; D
this; * return
x.n) n! (this- if
x.label); label, this- , %d" %d : e ("\nAdunar Box AfxMessage
p; * MR
k; D, i, int
{
) x & (MR operator :: MR & MR
> +
> >
+ + <

>
> +
+
p = new MR (this ->n, D, tis ->label+x.label);
for (i = 0; i <this-> dim; i ++)
{
p-> 1[i]=this->1[i];
p-> c[i]=this->c[i];
p-> e[i]=this->e[i];
}
k=this->dim;
for(i=0; i<x.dim; i++)
{
D=Found(x.1[i], x.c[i],this->dim,thois->1, this->c);
if(D)
p->e[D-1]+=x.e[i];
else
{
p->1[k]=x.1[i];
p->c[k]=x.c[i];
p->e[k]=x.e[i];
k++;
}
}
Sortare(p->1,p->c,p->e,p->dim);
x.FileWrite(x.txt);
this->FileWrite(this.txt);
p->FileWrite(p.txt);
return *p;
{
Implementarea operatorului de scderea este absolut similar celui de adunare, singura
diferen fiind accea c n cazul elementelor comune se face scaderea lor, n locul adunrii.
Transpunerea matricelor rare este similar celei efectuate pe structr tablou, constnd
n inversarea indicilor de linie i coloan ntre ei. n cazul de fa se inverseaz pointeriii la
masivele de ntregi reprezentnd liniile, respectiv coloanele elementelor nenule:
MR&MR::operator ++()
{
int*p;
AfxessageBox(\nTraspunere. . .);
p=this->1;this->1=this->c;this->c=p;
return *this;
}
5. Implementarea i inversarea matricelor rare
Pentru nmulirea matricei rare A, (m, 1) dimensional, cu matricea rar B, (l, n)
dimensional, se utilizeaz o modificare a procedurii standard, considernd influena liniilor
matricei A asupra matricei produs C, (m,n) dimensional, prin coloanele matricei B.
Procedura standard de nmulire se modific astfel nct n bucla intern s se execute toate
operaiile corespunztoare unui element al matricei A. ntruct elementul aik al matricei A poate
conntribui la formarea tuturor elementelor liniei i a matricei C, se determin mai nti aceast
contribuie dup care se continu cu urmtorul element al liniei i a matricei A, pn la
determinarea complet a liniei i a matricei C.
Acest principiu este utilizat n implementarea operatorului de nmulire a matricelor
rare din cadrul clasei MR prezentate n paragraful anterior. Se prezint n continuare acest
operator.
MR& operator * (MR &x)
int i, j, k, D;
tip S, R;
long T;
Mr *p, * q;
printf (\nnmulire : &d * *d, this->label, x.label);
if (this ->n!=x.n)
return *this;
// Pas 1 : Cte elemente va avea matricea final?
D=0;
for(i=0; i<this->dim; i++)
for(j=0; j<x.dim; j++)
if(this->c[i] ==x.1[j])
D++;
// Sunt cel mult D.
p=new MR(this->n, D this->label * x. label);
// pas 2 : Calcul efectiv.
// Se ia fiecare element din A i se nmulete cu tot ce
// se poate din B
// Elem. p -> e[i] trebuie s fie (i sunt) nule dup iniializare
R=0;
for (i =0; i<this->dim; i++)
for (j=0;j<x.dim; j++)
if(this->c[i]==x.1[j]
{
T=Found(this->1[i], x.c[j],D, p->1, p->c);
if(T)
if(p->e[T-1]) // deja iniializat
p->[T-1]+=this->e[i]*x.e[j]
else // se face iniializarea
{
p->1 [R]=this->1[i];
p->c[R]=x.c[j];
p->e[R]=this->e[i] *x.e[j];
R++;
}
yyy
x2 xx

yyy
x1 xx

else
{
p->1[R]=this->1[i];
p->c[R]x.c[j];
p->e[R]=this->e[i]
*x.e[j];
R++;
}
}
else
if(this->c[i] <x.1[j])) // x e totusi sortat
j=x.dim;
// Se scot zerourile i se sorteaz
D=p->dim;
for(i=0; i<p->dim; i++)
if (!p->e[i])
D- -;
q=new MR(this->n,D, this->label-x.label);
for(i=0; i<p->dim; i++)
if(p->e[i])
{
D- - ;
q->1[D]=p->1[i];
q->c[D]=p->c[i];
q->e[D]=p->e[i];
}
delete p;
Sortare (q->1, q->c, q->e, q->dim;
return *q;
{
Prin analiza acestui operator se constat c matricea rezultat pstreaz structura de
matrice rar (zerourile aprute au fost eliminate).
Pentru implementarea operatorului de inversare s-a folosit algoritmul lui Krlov. Acesta
const n parcurgerea unui numr de pai egal cu dimensiunile matricei:
1: A1 = A
1 1 1 1 1
A * p I B ) tr(A
1
1
p
2: A2 = A*B1
) (
2
1
2 2
A tr p
B2 = I p2 * A2
. . .
n-1 An-1 = A*Bn-2
1 n 1 n 1 n 1 n 1 n
A * p I B ) tr(A
1 n
1
p

n: An = A* Bn-1
n n n n
A * p I B tr(A)
n
1
p
Prin tr (A) se nelege urma matricei A (suma elementelor diagonale) iar I reprezint matricea
unitate de aceeai dimensiune cu matricea A.
Krlov a demonstrat c dup parcurgerea celor n pai, Bn este o matrice idenitic nul. de
aici rezult inversa matricei A:
A
-1
= pn * Bn-1 (10)
Se prezint n continuare operatorul de inversare a matricelor rare care implementeaz
algoritmul prezent.
MR & MR::operator ! ()
{
MR A(n, dim, label), *B,E(n,n,1), T(n,dim, label);
float P;
AfxMessageBox(Inversare);
B=new MR(n,dim,label);
yyy
x2 xx

yyy
x1 xx

E=this->I(n);
T<=*this;
P=T.Tras();
B=T-E*P;
T.FileWrite(A.txt);
(*B). FileWrite(B.txt);
for(int k=2; k<n;k++)
{
A=T*(*B);
P=((float) 1/ float)K)*A.Tras();
B=A-EP;
A.FileWrite (A.txt);
(*).FileWrite(B.txt);
}
A=T*(*B);
A.FileWrite(A.txt);
P=((float)1/(float)n*Atras();
B=(B*)((float) 1/(float)P;
A.FileWrite(A.txt);
(*B).FileWrite(B.txt);
return *B;
}
Avantajele acestui algoritm constau n simplitatea implementrii i precizia rezultatelor, datorat
folosirii unui numr redus de operaii de mprire.
6. Estimarea parametrilor unei regresii statistice folosind clasa MR
Se consider datele din tabelul 1 ce caracterizeaz cinci ntreprinderi din punctul de
vedere al productivitii (y), al numrului de utilaje de mare performan deinute (x1) i al
veniturilor suplimentare acordate salariailor (x2). Se dorete determinarea unei funcii care s
caracterizeze dependena dintre productivitate i celelalte dou variabile considerate
independente (numr de utilaje i venituri suplimentare).
Tabelul 1
y productivitatea muncii (creteri procentuale) 1 2 5 6 7
x1 utilaje de mare randament (buci) 2 4 4 4 5
x2 venituri suplimentare (mil. lei) 1 1 3 5 5
Pentru a specifica forma funciei, se analizeaz pe cale grafic dependena variabilei
efect (y) n raport cu fiecare dintre variabilele cauzale.
Figura 1 Dependena y=f(x1), y=f(x2)
ntruct norul de puncte din fiecare reprezentare grafic sugereaz o linie dreapt,
specificm modelul astfel:
yi = a0 + a1x1i + a2x2i + ui (11)
unde ui reprezint o variabil rezidual ce caracterizeaz influena altori factori asupra
variabilei efect y, factori care din diverse motive nu pot fi luai n considerare.
Dac simbolizm
y
valorile ajustate, rezultate n urma aplicrii modelului liniar,
specificm modelul astfel:
2i 2 1i 1 0 i
x a x a a y + +
(12)
yyy
x2 xx

yyy
x1 xx

Relaia (12) se scrie pentru fiecare set de valori prezentate n tabelul 1, rezultnd:

,
_

,
_

,
_

,
_

n n n n n
u
u
u
a
a
a
x x
x x
x x
y
y
y

2
1
1
0
2 2
1 1
2
1
2 1 1
2 1 1
2 1 1
(13)
Aadar,
Y = XA + U (14)
iar
A X Y
(15)
Determinarea dependenei dintre variabila efect i variabilele cauz nsemn
determinarea valorilor numerice ale parametrilor
1 0
a , a
i
2
a
. n acest scop se utilizeaz
metoda celor mai mici ptrate. [3] Aceast metod presupune minimizarea expresiei

t
2
t
u
,
adic, matriceal, U U. Dar
( ) ( ) A X Y A X Y U U


(16)
unde prin U' s-a notat transpusa matricei U.
n [3] se demonstreaz c prin minimizarea relaiei (16) se ajunge la expresia:
( ) Y X X X A
1


(17)
O determinare ct mai precis a matricei parametrilor unei regresii presupune existena
unui numr foarte mare de date (numr mare de linii n matricea X). n multe cazuri practice
valorile acestor date sunt nule, fapt ce justific implementarea relaiei (17) pe o structur de
matrice rare. Avnd deja definiii operatorii de transpunere, nmulire i inversare,
implementarea relaiei (17) presupune scrierea unei singure linii de cod:
( ) ( ) ( ) ( ) Y * X * X * X ! A + + + +
(18)
Aadar, pentru aflarea matricei
A
sunt necesare dou operaii de transpunere, trei
nmuliri i o inversare. Matricele X i Y asupra crora se opereaz au n multe dintre cazurile
practice o densitate foarte mic, astfel c este pe deplin justificat folosirea unor structuri de
memorare specifice matricelor rare.
7. Concluzii
Asistm n prezent la un fenomen care tinde s ating tot mai multe domenii de
activitate: necesitatea de a cunoate ct mai precis anumii factori sau parametri ce
caracterizeaz domeniul respectiv, care pn nu de mult erau fie considerai aleatori, fie nu se
punea problema determinrii lor, considerat a fi imposibil. Cunoaterea acestor factori ofer o
descriere mai detaliat a sistemului n care se lucreaz, permind n acest fel o mai bun
activitate de control i comand a acestuia.
n cele mai multe dintre cazuri baza de calcul a acestor factori o constituie statistic
matematic i teoria probabilitilor, ceea ce conduce la necesitatea rezolvrii unor probleme
liniare de foarte mari dimensiuni. Caracterul de raritate al structurilor implicate n rezolvarea
problemelor, datorat caracteristicilor reale ale sistemelor, la care se adaug necesitatea unei
rezolvri rapide, n concordan cu dinamica crescnd a sistemelor actuale, justific pe deplin
introducerea n aplicaiile informatice asociate a unor structuri de date adaptate acestor
particulariti.
Softul orientat spre lucrul cu matrice rare exploateaz caracterul de raritate al
structurilor manipulate, oferind un dublu avantaj: memorie i timp. n ultimii ani memoria nu
mai constituie o problem, ns timpul necesar calculelor, odat cu apariia sistemelor n timp
real, se dovedete a fi tot mai mult o resurs critic.
Referitor la lucrul cu matrice n general, n cadrul unui sistem n care timpul reprezint
o resurs critic, se poate imagina un soft care s fac o evaluare anterioar calculelor asupra
densitii matricei, i, n funcie de aceasta, s decid asupra structurilor de date ce vor fi folosite
pentru memorare i efectuarea calculelor, astfel nct timpul afectat calculelor s fie minim.
Suma si diferena matricelor rare
Tendinta de a micsora spatiul ocupat de anumite date in memoria unui calculator a dus la
proiectarea si dezvoltarea a multor algoritmi de compresie .
O matrice rara este o matrice ce contine mai mult de doua treimi valori nule.
O astfel de matrice se poate comprima foarte simplu prin inlocuirea sa in memorie cu trei
vectori cu dimensiuni egale cu numarul de elemente nenule din matrice . Pe fiecare pozitie din
cei trei vectori se vor gasi rangul liniei, in primul vector, rangul coloanei, in al doilea vector si
elementul nenul din matrice in cel de-al treilea vector. Al treilea vector va fi ordonat dupa
primul vector si dupa cel de-al doilea vector.
Programul contine urmatoarele proceduri :
O procedura de alocare si initiere de la tastatura a unei matrice:
void incarcare(float **&a,int m,int n) care primeste ca parametri un pointer catre o
matrice de numere reale prin referinta pentru a permite modificarea sa si dimensiunile matricei;
O procedura care verifica daca o matrice este rara:
int ifrar(float **a,int m,int n) care primeste ca parametri un pointer la matrice si
dimensiunile matricei si returneaza numarul de elemente nenule din matrice daca aceasta
este rara sau 0 daca nu;
O procedura care transforma o matrice rara in cei trei vectori despre care am vorbit mai
sus:
void matrara(float **a,int m,int n,int k,int *&v1,int *&v2,float *&v3)
care primeste ca parametri un pointer la matrice, dimensiunile matricei, numarul de
elemente nenule din matrice si cate un pointer la fiecare din cei trei vectori care rezulta,
primiti prin referinta ;
O procedura care dezaloca o matrice alocata dinamic:
void distruge(float **&a,int m,int n) care primeste ca parametri un pointer la matrice
transmis prin referinta si dimensiunile ei;
O procedura care aduna doua matrice rare ce au fost in prealabil comprimate :
int adunare(float *vel1,int *vc1,int *vl1,int n1,float *vel2,int *vc2,int *vl2,int n2,float
*&velr,int *&vcr,int *&vlr) care primeste ca parametri trei pointeri catre cei trei vectori
corespunzatori primei matrice si dimensiunea lor, trei pointeri catre cei trei vectori
corespunzatori celei de-a doua matrice si dimensiunea lor si trei pointeri catre trei
vectori corespunzatori matricei rezultate si returneaza dimensiunea vectorilor rezultati;
O procedura care calculeaza diferenta dintre doua matrice rare comprimate in prealabil:
int scadere(float *vel1,int *vc1,int *vl1,int n1,float *vel2,int *vc2,int *vl2,int n2,float
*&velr,int *&vcr,int *&vlr) avand aceiasi parametri de intrare si returnand tot
dimensiunea vectorilor rezultati.
Programul urmeaza urmatorul algoritm:
P1-Introducerea de la tastatura a dimensiunilor matricelor( matricele trebuie sa aiba
aceleasi dimensiuni pentru a le putea aduna sau scadea) ;
P2-Alocarea si initializarea primei matrice prin procedura incarcare;
P3-Verificarea primei matrice daca este rara prin procedura ifrar si daca nu este se
afiseaza ca nu este rara si se incheie rularea programului, iar daca este se trece la pasul urmator;
P4-Compresia primei matrice prin procedura matrar ;
P5-Dezalocarea primei matrice prin procedura distruge;
P6-Alocarea si initializarea celei de-a doua matrice prin procedura incarcare;
P7-Verificarea celei de-a doua matrice daca este rara prin procedura ifrar si daca nu
este se afiseaza ca nu este rara si se incheie rularea programului, iar daca este se trece la pasul
usmator;
P8-Compresia celei de-a doua matrice prin procedura matrar ;
P9-Dezalocarea celei de-a doua matrice prin procedura distruge;
P10-Suma celor doua matrice prin procedura adunare;
P11-Diferenta celor doua matrice prin procedura scadere.
Procedura adunare are urmatorii pasi:
P1-Alocarea celor trei vectori corespunzatori rezultatului;
P2- Parcurgerea vectorilor primei matrice, iar pentru fiecare iteratie se parcurg pasii
P3-P5;
P3- Parcurgerea vectorilor celei de-a doua matrice pana la egalarea rangului liniei si
coloanei elementului curent din prima matrice si copierea lor in vectorii rezultanti;
P4-Daca rangul liniei si coloanei sunt aceleasi la elementele curente din cele doua
matrice se aduna elementele si se introduce rezultatul in vectorii rezultanti si se sare la P6, altfel
se trece prin pasul P5;
P5-daca nu exista in cea de-a doua matrice element nenul pe linia si coloana
corespunzatoare elementului curent din prima matrice se copiaza acest element si pozitia sa in
matrice in vectorii rezultanti;
P6-Dupa ce se termina de parcurs vectorii primei matrice, se verifica daca in cea de-a
doua matrice sunt elemente de rang al liniei sau coloanei mai mare decat al ultimului element
din vectorii primei matrice si daca exista astfel de elemente se vor memora aceste elemente in
continuare in vectorii matricei rezultate;
P7-Se returneaza lungimea vectorilor rezultati;
Procedura scadere urmeaza pasii:
P1-Alocarea si initializarea unui vector auxiliar cu valorile vectorului de elemente
corespunzator celei de-a doua matrice, luate cu semn schimbat;
P2-Efectuarea diferentei prin adunarea primei matrice cu matricea a doua inmultita cu
-1;
P3-Returnarea lungimii vectorilor rezultati.

#include<iostream.h>
//procedura de compresie a unei matrice rare(normalizarea sa)
void matrara(float a[10][10],int m,int n,int v1[34],int v2[34],float v3[34])
{
int k=0;
for(int i=0;i<n;i++)
for(int j=0;j<m;j++)
if(a[i][j])
{
v1[k]=i; //initiere
v2[k]=j; //vectorilor
v3[k]=a[i][j];//cu elementele
nenule ale matricei
k++;
}
}
//procedura dealocare si incarcare de la tastatura a unei matrice
void incarcare(float a[10][10],int m,int n)
{
for(int i=0;i<n;i++)
for(int j=0;j<m;j++)
{
cout<<"Introduceti elementul:"<<i+1<<","<<j+1<<" :
";//introducerea
cin>>a[i][j];
//datelor de la tastatura
}
}
//procedura de verificare a unei matrice daca este rara
int ifrar(float a[10][10],int m,int n)
{
int k=0;
for(int i=0;i<n;i++) //contorizarea
for(int j=0;j<m;j++) //elementelor
if(!a[i][j]) k++; //nule
if(k>m*n*2/3)
return m*n-k; //returneaza numarul de elemente nenule
else
return 0;
}
//procedura de adunare a doua matrici rare memorate in vectori
int adunare(float *vel1,int *vc1,int *vl1,int n1,float *vel2,int *vc2,int *vl2,int n2,float
velr[67],int vcr[67],int vlr[67])
{
int l=0,k=0;
float a;
for(int i=0;i<n1;i++)// parcurgerea vectorilor primei matrice
{
for(int j=k;(vl1[i]>vl2[j])||((vl1[i]==vl2[j])&&(vc1[i]>vc2[j]));j++,l+
+,k++)//parcurgerea vectorilor
{
// celei de-a doua matrice
//pana la egalarea rangului
velr[l]=vel2[j];
//liniei si coloanei elementului
vlr[l]=vl2[j];
//primei matrice
vcr[l]=vc2[j];
}
if((vl1[i]==vl2[j])&&(vc1[i]==vc2[j])) //daca rangul
liniei si coloanei sunt
{
// aceleasi se aduna elementele
a=vel1[i]+vel2[j];
if(a)
{
velr[l]=a;
vlr[l]=vl2[j];
vcr[l]=vc2[j];
l++;
}
k++;
}
else
{
velr[l]=vel1[i]; //daca nu exista in cea de-a doua
matrice element nenul
vlr[l]=vl1[i]; //pe linia si coloana
corespunzatoare elementului din
vcr[l]=vc1[i]; // vectorii primei
matrice
l++;
}
}
if(k!=n2) //daca in cea
de-a doua matrice sunt elemente de
for(i=k;i<n2;i++) //rang al liniei sau
coloanei mai mare decat al
{
//ultimului element din vectorii primei matrice
velr[l]=vel2[i]; //se vor memora aceste elemente
in continuare in
vlr[l]=vl2[i]; //vectorii matricei
rezultate
vcr[l]=vc2[i];
l++;
}
return l; //returneaza lungimea vectorilor rezultati
}
//procedura de scadere a doua matrice rare memorate fiecare in cate trei vectori
int scadere(float *vel1,int *vc1,int *vl1,int n1,float *vel2,int *vc2,int *vl2,int n2,float
velr[67],int vcr[67],int vlr[67])
{
float *vaux=new float[n2]; //se foloseste un vector auxiliar in care se
introduc
//valor
ile nenule cu semn schimbat din prima matrice
for(int i=0;i<n2;i++)
vaux[i]=-vel2[i];
int k=adunare(vel1,vc1,vl1,n1,vaux,vc2,vl2,n2,velr,vcr,vlr);//se face scaderea
prin
//adunare: a-b=a+(-b)
delete [n2]vaux;//se dezaloca vectorul auxiliar
return k;//se returneaza dimensiunea vectorilor rezultati
}
//***************************************************************************
******************
void main ()
{
float x[10][10],y[10][10],vel1[34],vel2[34],vela[67],vels[67];//se declara
pointerii la cele doua matrice initiale
//si la
vectorii de elemente
int n,m,vl1[34],vl2[34],vc1[34],vc2[34],vca[67],vla[67],vcs[67],vls[67];//se
declara dimansiunile matricelor
//si pointerii la vetorii de ranguri ale liniilor si cocloanelor
cout<<"Introduceti numarul de linii(<=10) :"; //se
introduc de la tastatura
cin>>n;
//numarul de linii si
cout<<"Introduceti numarul de coloane(<=10) :"; // de coloane
cin>>m;
incarcare(x,m,n);// se aloca si se initializeaza de la tastatura prima matrice
int l1=ifrar(x,m,n);//se verifica daca prima matrice este rara
if(l1)
{
matrara(x,m,n,vl1,vc1,vel1);//se transforma prima matrice in
trei vectori
for(int i=0;i<l1;i++) //se afiseaza cei trei
vectori corespunzatori
cout<<"\n"<<vl1[i]<<" "<<vc1[i]<<"
"<<vel1[i]; //primei matrice
incarcare(y,m,n);// se aloca si se initializeaza de la tastatura
a doua matrice
int l2=ifrar(y,m,n);//se verifica daca a doua matrice este rara
if(l2)
{
matrara(y,m,n,vl2,vc2,vel2);//se
transforma a doua matrice
//in trei vectori
for(int i=0;i<l2;i++)//se afiseaza cei trei
vectori corespunzatori celei
cout<<"\n"<<vl2[i]<<" "<<vc2[i]<<"
"<<vel2[i];//de-a doua matrice
int
la=adunare(vel1,vc1,vl1,l1,vel2,vc2,vl2,l2,vela,vca,vla);//se aduna
//cele doua
matrice rezultand tot trei vectori in care va
//fi memorata
if(!(la<m*n/3))cout<<"Matricea suma nu
este rara ";//se verifica daca
//matricea rezultata este rara
cout<<"\n";
for( i=0;i<la;i++) //se afiseaza vectorii
rezultati
cout<<"\n"<<vla[i]<<"
"<<vca[i]<<" "<<vela[i];
int
ls=scadere(vel1,vc1,vl1,l1,vel2,vc2,vl2,l2,vels,vcs,vls);//se scad
//cele doua
matrice rezultand tot trei vectori in care va
//fi memorata
if(!(ls<m*n/3))cout<<"Matricea diferenta
nu este rara ";//se verifica daca
//matricea rezultata este rara
cout<<"\n";
for( i=0;i<ls;i++) //se afiseaza vectorii
rezultati
cout<<"\n"<<vls[i]<<"
"<<vcs[i]<<" "<<vels[i];
}
else
cout<<"Nu este matrice rara!!!";
}
else
cout<<"Nu este matrice rara!!!";
}
#include<iostream.h>
//procedura de compresie a unei matrice rare(normalizarea sa)
void matrara(float **a,int m,int n,int k,int *&v1,int *&v2,float *&v3)
{
int l=m*n-k;
k=0;
v1=new int[l];//alocare
v2=new int[l];// vectori
v3=new float[l];// rezultati
for(int i=0;i<n;i++)
for(int j=0;j<m;j++)
if(a[i][j])
{
v1[k]=i; //initiere
v2[k]=j; //vectorilor
v3[k]=a[i][j];//cu elementele
nenule ale matricei
k++;
}
}
//procedura dealocare si incarcare de la tastatura a unei matrice
void incarcare(float **&a,int m,int n)
{
int k=0;
a=new float*[n]; //alocarea
for(int i=0;i<n;i++) //matricei
a[i]=new float[m];
for(i=0;i<n;i++)
for(int j=0;j<m;j++)
{
cout<<"Introduceti elementul:"<<i+1<<","<<j+1<<" :
";//introducerea
cin>>a[i][j];
//datelor de la tastatura
}
}
//procedura de verificare a unei matrice daca este rara
int ifrar(float **a,int m,int n)
{
int k=0;
for(int i=0;i<n;i++) //contorizarea
for(int j=0;j<m;j++) //elementelor
if(!a[i][j]) k++; //nule
if(k>m*n*2/3)
return m*n-k; //returneaza numarul de elemente nenule
else
return 0;
}
//procedura de dezalocare a unei matrice
void distruge(float **&a,int m,int n)
{
for(int i=0;i<n;i++)
delete [m]a[i];
delete [n]a;
}
//procedura de adunare a doua matrici rare memorate in vectori
int adunare(float *vel1,int *vc1,int *vl1,int n1,float *vel2,int *vc2,int *vl2,int n2,float
*&velr,int *&vcr,int *&vlr)
{
int l=0,k=0;
float a;
vlr=new int[n1+n2];
vcr=new int[n1+n2];
velr=new float[n1+n2];
for(int i=0;i<n1;i++)// parcurgerea vectorilor primei matrice
{
for(int j=k;(vl1[i]>vl2[j])||((vl1[i]==vl2[j])&&(vc1[i]>vc2[j]));j++,l+
+,k++)//parcurgerea vectorilor
{
// celei de-a doua matrice
//pana la egalarea rangului
velr[l]=vel2[j];
//liniei si coloanei elementului
vlr[l]=vl2[j];
//primei matrice
vcr[l]=vc2[j];
}
if((vl1[i]==vl2[j])&&(vc1[i]==vc2[j])) //daca rangul
liniei si coloanei sunt
{
// aceleasi se aduna elementele
a=vel1[i]+vel2[j];
if(a)
{
velr[l]=a;
vlr[l]=vl2[j];
vcr[l]=vc2[j];
l++;
}
k++;
}
else
{
velr[l]=vel1[i]; //daca nu exista in cea de-a doua
matrice element nenul
vlr[l]=vl1[i]; //pe linia si coloana
corespunzatoare elementului din
vcr[l]=vc1[i]; // vectorii primei
matrice
l++;
}
}
if(k!=n2) //daca in cea
de-a doua matrice sunt elemente de
for(i=k;i<n2;i++) //rang al liniei sau
coloanei mai mare decat al
{
//ultimului element din vectorii primei matrice
velr[l]=vel2[i]; //se vor memora aceste elemente
in continuare in
vlr[l]=vl2[i]; //vectorii matricei
rezultate
vcr[l]=vc2[i];
l++;
}
k=n1+n2-l;
/*delete [k](vlr+l);
delete [k](vcr+l);
delete [k](velr+l);*/
return l; //returneaza lungimea vectorilor rezultati
}
//procedura de scadere a doua matrice rare memorate fiecare in cate trei vectori
int scadere(float *vel1,int *vc1,int *vl1,int n1,float *vel2,int *vc2,int *vl2,int n2,float
*&velr,int *&vcr,int *&vlr)
{
float *vaux=new float[n2]; //se foloseste un vector auxiliar in care se
introduc
//valor
ile nenule cu semn schimbat din prima matrice
for(int i=0;i<n2;i++)
vaux[i]=-vel2[i];
int k=adunare(vel1,vc1,vl1,n1,vaux,vc2,vl2,n2,velr,vcr,vlr);//se face scaderea
prin
//adunare: a-b=a+(-b)
delete [n2]vaux;//se dezaloca vectorul auxiliar
return k;//se returneaza dimensiunea vectorilor rezultati
}
//***************************************************************************
******************
void main ()
{
float **x,**y,*vel1,*vel2,*vela,*vels;//se declara pointerii la cele doua
matrice initiale
//si la
vectorii de elemente
int n,m,*vl1,*vl2,*vc1,*vc2,*vca,*vla,*vcs,*vls;//se declara dimansiunile
matricelor
//si pointerii la vetorii de ranguri ale liniilor si cocloanelor
cout<<"Introduceti numarul de linii:"; //se introduc de
la tastatura
cin>>n;
//numarul de linii si
cout<<"Introduceti numarul de coloane:"; // de coloane
cin>>m;
incarcare(x,m,n);// se aloca si se initializeaza de la tastatura prima matrice
int l1=ifrar(x,m,n);//se verifica daca prima matrice este rara
if(l1)
{
matrara(x,m,n,l1,vl1,vc1,vel1);//se transforma prima matrice
in trei vectori
distruge(x,m,n); //se dezaloca prima matrice
for(int i=0;i<l1;i++) //se afiseaza cei trei
vectori corespunzatori
cout<<"\n"<<vl1[i]<<" "<<vc1[i]<<"
"<<vel1[i]; //primei matrice
incarcare(y,m,n);// se aloca si se initializeaza de la tastatura
a doua matrice
int l2=ifrar(y,m,n);//se verifica daca a doua matrice este rara
if(l2)
{
matrara(y,m,n,l2,vl2,vc2,vel2);//se
transforma a doua matrice
//in trei vectori
distruge(y,m,n);//se dezaloca a doua
matrice
for(int i=0;i<l2;i++)//se afiseaza cei trei
vectori corespunzatori celei
cout<<"\n"<<vl2[i]<<" "<<vc2[i]<<"
"<<vel2[i];//de-a doua matrice
int
la=adunare(vel1,vc1,vl1,l1,vel2,vc2,vl2,l2,vela,vca,vla);//se aduna
//cele doua
matrice rezultand tot trei vectori in care va
//fi memorata
if(!(la<m*n/3))cout<<"Matricea suma nu
este rara ";//se verifica daca
//matricea rezultata este rara
cout<<"\n";
for( i=0;i<la;i++) //se afiseaza vectorii
rezultati
cout<<"\n"<<vla[i]<<"
"<<vca[i]<<" "<<vela[i];
int
ls=scadere(vel1,vc1,vl1,l1,vel2,vc2,vl2,l2,vels,vcs,vls);//se scad
//cele doua
matrice rezultand tot trei vectori in care va
//fi memorata
if(!(ls<m*n/3))cout<<"Matricea diferenta
nu este rara ";//se verifica daca
//matricea rezultata este rara
cout<<"\n";
for( i=0;i<ls;i++) //se afiseaza vectorii
rezultati
cout<<"\n"<<vls[i]<<"
"<<vcs[i]<<" "<<vels[i];
}
else
cout<<"Nu este matrice rara!!!";
}
else
cout<<"Nu este matrice rara!!!";
}
4. ARTICOLUL STRUCTURA DE DATE NEOMOGEN I CONTINU
4.1. Structuri de date poziionale
Exist o diversitate de date cu care se caracterizeaz indivizii unei colectiviti.
Dup efectuarea unei analize detaliate, se conchide c un numr q de caracteristici sunt
suficiente pentru descrierea elementelor colectivitii. n continuare numim ablon de
descriere, o anumit ordine n care sunt nirate caracteristicile, ordine absolut necesar a fi
respectat la descrierea fiecrui element al colectivitii.
Fie caracteristicile C1, C2, .... Cq dispuse n ordinea care se constituie n ablonul
asociat descrierii indivizilor colectivitii considerate.
De exemplu. pentru descrierea materialelor existente n stoc, se consider
caracteristicile:
C1 - numele materialului
C2 - unitatea de msur
C3 - cantitatea existent n stoc la nceputul perioadei
C4 - preul unitar
C5 - data ultimei aprovizionri
C6 - intrrile de materiale
C7 - ieirile de materiale
nume articol nn
primul elem.
din ablon dd
al 2-lea elem.
din ablon dd
ultimul elem.
din ablon dd
. . . ..
C8 - codul materialului
C9 - stocul final
Deci q = 8; ablonul pentru introducerea datelor are elementele:
C8 C1 C2 C4 C3 C5 C6 C7
Caracteristica C9 nu e necesar pentru c rezult din calcule.
Aceste caracteristici sunt poziionale, n sensul c C8 este prima caracteristic n
ablon, C3 este a 5-a caracteristic n ablon, iar C7 este ultima caracteristic a ablonului.
La introducerea datelor, irurile de constante se constituie n cmpuri. Astfel, se
identific cmpul pentru codul materialului, format dintr-un numr fix de cifre, cmpul
numele materialului, ce are un numr de caractere care nu depesc o valoare
prestabilit,etc.
ablonul se descrie prin:
Caracteristic Natur dat Lungimea ca
nr.de car.
C8 cod material numr 5
C1 nume material ir caractere 20
C2 unitate msur ir caractere 3
C3 cantitate existent n stoc numr 6
C4 pre unitar numr real 4+2
C5 data ultimei aprovizionri ir caractere 9
C6 intrri numr 6
C7 ieiri numr 6
C9 stoc final numr 9
nume articol nn
primul elem.
din ablon dd
al 2-lea elem.
din ablon dd
ultimul elem.
din ablon dd
. . . ..

Observm c cele 8 caracteristici difer ca natur, ca lungime a irului de simboluri ce compun cmpurile i ocup n cadrul
ablonului poziii distincte.
Datele grupate n ablon cu poziia fiecreia specificat, formeaz o structur de date de tip articol.
Modelul grafic asociat articolului este:
Observm c pe ultimul nivel se afl date elementare specificate prin nume i tip. Structura, n ansamblul ei, are un nume i se
definete distinct, ceea ce urmeaz reprezentnd componentele de la nivelul al doilea.
typedef struct Material
{
int cod;
char nume[20];
char um[3];
float pre;
int cont;
int intrri;
int ieiri;
};
Lg(material) = lg(cod) + lg(nume) + lg(um) + lg(pret) +
Lg(cont) + lg(intrari) + lg(iesiri) +
n cazul n care compilatorul face o alocare neoptimal reprezint numrul biilor impui de alinierea cerut de fiecare
cmp precedent care are un alt tip dect char, byte, string. n cazul n care are loc optimizare n faza de compilare, devine nul.
Adr(cmp i) = adr(cmp 1) +

1
1
n
j
lg(cmp j) + j
Unde:

'

+
+

alinierea cere nu cmpj care n cazul n


j cmpului alinierea de cerut baitul reprez
j
1 0
1 int 1

Dac datele de la nivelul al doilea le regsim sub numele de cmpuri elementare, la nivelul superior data este numit dat
de grup.
n unele situaii fiecrui nivel i se asociaz un numr, numit numr de nivel. Pentru nivelele inferioare se asociaz
numere naturale mai mari dect cel asociat nivelelor superioare. Unui nivel i se ataeaz un numr sau un interval de numere.
Descrierea n orice situaie rmne poziional.
Astfel, pentru exemplul dat se folosesc descrieri cu numere de nivel:
01 material
02 cod
02 nume
02 um
02 pre
02 cantitate
02 intrri
02 ieiri
01.................
Terminarea descrierii structurii, este marcat de apariia unui numr de nivel care delimiteaz nceputul altei structuri,
sau o instruciune de program, proprie limbajului, care vine s marcheze nceputul unei alte secvene program.
O alt descriere este:
7 material
nume articol nn
primul elem.
din ablon dd
al 2-lea elem.
din ablon dd
ultimul elem.
din ablon dd
. . . ..
data dd
zi zz luna ll an aa
adresa aa
data_stabilirii dd strada ss numr nn telefon tt ora oo
zi zz luna ll an aa
(*) ((
persoana pp
data
naterii nn
locul
naterii nn
vrsta vv
data
angajrii aa
adresa
acual aa
(*) (( (*) (( (**) ((
data
naterii nn
strada ss numr nn telefon tt ora oo
(**) ((
8 cod
9 nume
10 um
8 pre
10 cantitate
9 intrri
9 ieiri
4..........................
unde, pentru primul nivel se utilizeaz numerele 4,5,6 sau 7, iar pentru al doilea nivel, sunt utilizate numerele 8,9 sau 10.
La acest nivel de descriere a articolelor putem observa c o dat elementar este un articol cu cmpuri de acelai tip.
Astfel:
typedef struct a
{
int b;
};
typedef struct c
{
int c1;
int c2;
int c3;
int c4;
int c5;
};
i
a x;
c w,y;
conduc la aceleai rezervri de zone de memorie pentru x i y ca definiiile:
int u;
int t[5],v[5];
adr(c4) = adr(c1) + lg(c1) + lg(c3) =
= adr(c1) + (4-1)*lg(int)
iar
adr(v[4]) = adr(v[1]) + (4-1)*lg(int)
Cmpurile unui articol se numesc membrii articolului, iar referirea lor se face folosind operatorul de referire . (punct).
n exemplul considerat, w i y sunt variabile de tip C, iar t i v sunt masive, fiecare avnd 5 elemente. Prin w.C4 se refer
cmpul C4 al variabilei w, iar prin y.C1 se refer cmpul C1 al variabilei y.
Dac se ia n considerare tipul de variabil articol muncitor i se face definirea:
Material m;
m.cod, m.pre, sunt referiri ale cmpurilor ce alctuiesc variabila m definit ca avnd tipul material.
Observm c articolul este un tip de dat generic, pe care prin forma de definire a cmpurilor l putem folosi pentru a
obine tipuri derivate de date.
Astfel, material i C sunt tipuri derivate de date corespunztoare tipului generic STRUCT.
Definirea acestui tip pune n eviden:
- componentele, (cmpurile) care-l alctuiesc;
- natura cmpurilor;
- poziia cmpurilor.
ntr-un cuvnt, structura sau ablonul datelor.
Variabilele definite pentru un tip derivat ocup atta memorie ct rezult din lungimile cmpurilor nsumate i corectate
cu alinierea i au n componen exact aceleai elemente folosite la descrierea tipului, ca membri ai fiecrei variabile.
Descrierea unui tip derivat nu nseamn rezervare de memorie, ci stocare de informaie privind elementele care l
definesc.
Definirea variabilelor de tipul derivat descris anterior, efectueaz rezervare de memorie.
4.2. Structuri de date ierarhizate
Datele de tip articol sunt ierarhizate pe dou sau mai multe nivele. Pentru a obine descrierea mai multor nivele este
necesar ca la fiecare nivel inferior s fie posibil enumerarea de date elementare sau date de grup. Datele de grup e necesar s fie
descrise deja nainte de a le folosi, dar n unele cazuri particulare, descrierea lor se efectueaz ulterior folosirii.
Astfel se definesc tipurile:
struct data
{
int zi;
int luna;
int an;
a =
111

111
b =
nnn
c =
mmm

111

111




student ss
nume nn data_naterii dd data_admiterii dd
zi zz luna ll an aa zi zz luna ll an aa
data dd
zi zz luna ll an aa
adresa aa
data_stabilirii dd strada ss numr nn telefon tt ora oo
zi zz luna ll an aa
(*) ((
persoana pp
data
naterii nn
locul
naterii nn
vrsta vv
data
angajrii aa
adresa
acual aa
(*) (( (*) (( (**) ((
data
naterii nn
strada ss numr nn telefon tt ora oo
(**) ((
};
struct adresa
{
data Data_stabilirii;
char Strada[30];
int Numr;
char Telefon[8]; char
Ora[30]; };
struct persoana
{
data Data_naterii ;
adresa Locul_naterii;
int Vrsta;
data data_angajrii;
adresa adresa_actual;
};
Acestor tipuri le corespund modelele grafice:
Definirea ulterioar specificrii datelor de grup, se face ca n exemplul:
01 persoana
02 data_stabilirii
03 zi
03 luna
03 an
02 locul naterii
03 data_naterii
04 zi
04 luna
04 an
03 strada
03 numr
03 telefon
03 ora
02 vrsta
02 data_angajrii
03 zi
03 luna
03 an
02 adresa_actual
03 data_stabilirii
04 zi
04 luna
04 an
03 strada
03 numr
03 telefon
03 ora
Oricare ar fi modalitatea de descriere a structurii arborescente, aceasta trebuie s rmn n continuare neambigu.
Dac se accept ca definiie a lungimii elementului de la nivelul i
) 1 , , ( ) , lg(
0
+

i j y i x
ni
j
unde prin xj nelegem elementul yj de pe nivelul i+1, astfel nct
xxx
x[0] xx x[1] xx x[2] xx x[14] xx x[19] xx
nume nn vrsta vv facult ff an_studiu aa nume nn vrsta vv facult ff an_studiu aa
a =
111

111
b =
nnn
c =
mmm

111

111
d =
kkk




student ss
nume nn data_naterii dd data_admiterii dd
zi zz luna ll an aa zi zz luna ll an aa
data dd
zi zz luna ll an aa
adresa aa
data_stabilirii dd strada ss numr nn telefon tt ora oo
zi zz luna ll an aa
(*) ((
persoana pp
data
naterii nn
locul
naterii nn
vrsta vv
data
angajrii aa
adresa
acual aa
(*) (( (*) (( (**) ((
data
naterii nn
strada ss numr nn telefon tt ora oo
(**) ((
cont(x) adr(y1)
rezult c, adresa unui element yj de pe nivelul i aparinnd date de grup k dintr-o structur de tip articol, se obine prin relaia:
( ) ( ) ( ) ( ) ( ) ( ) k i yh k i yk i y adr yj adr
j
h
k
k
+ + + +

, lg , lg , 1 0 ,
1
1
1
1
De exemplu, pentru articolul definit prin:
struct student
{
char nume[21];
data data_naterii ;
data data_admiterii;
};
Adresa cmpului data_admiterii.an se obine urmrind modelul grafic:
dup formula:
adr(student.data_admiterii.an,3)=adr(student.nume,2)+
+ lg(student.nume,2)+1+
+ lg(student.data_naterii,2)+ 2+
+ lg(student.data_naterii.zi)+ 3+
+ lg(student.data_naterii.luna)+ 4+
+ lg(student.nume,2)+ 21+1+4+4+4+
+2+4+3+4+4=41+1=42
pentru ca 2=3=4=0
Dac considerm punctul operator ca orice alt operator, construcia:
a.b.c.d
este o expresie care se evalueaz ca orice alt expresie aritmetic, logic sau raional. O astfel de expresie o numim expresie
referenial.
Expresia referenial se evalueaz de la stnga la dreapta, pentru c n final trebuie obinut o adres, referirea oricrui
operand fcndu-se fie prin numele su, dac abordarea este la nivel de limbaj, fie prin adres, dac analiza este din punctul de
vedere al programatorului interesat s cunoasc mecanismele proprii execuiei programelor.
Interpretarea expresiei:
a.b.c.d
este:
d este membru n structura de tip articol c
c este membru n structura de tip articol b
b este membru n structura de tip articol a
ceea ce ca model grafic i corespunde:
xxx
x[0] xx x[1] xx x[2] xx x[14] xx x[19] xx
nume nn vrsta vv facult ff an_studiu aa nume nn vrsta vv facult ff an_studiu aa
a =
111

111
b =
nnn
c =
mmm

111

111
d =
kkk




student ss
nume nn data_naterii dd data_admiterii dd
zi zz luna ll an aa zi zz luna ll an aa
( ) ( ) ( ) Tj j adr d c adr
k
j
, lg 1 .
1
1

+
( ) ( ) ( ) ( ) 1 , lg 1 .
1
1
adr Tj j adr c b adr
m
j
+

( ) ( ) ( ) ( ) j adr Tj j adr b a adr


n
j
+

, lg 1 .
1
1
( ) ( ) 1 adr a adr
adr(a.b.c.d) = adr(a.b) + adr(b.c) + adr(c.d) 2*adr(a)
adr(a.b.c.d) = adr(a) + adr(a.b) + adr(b.c) + adr(c.d) 3*adr(a)
adr(a.b.c.d) = adr(a) + [adr(a.b) - adr(a)] + [adr(b.c) adr(a)]+[adr(c.d)-adr(a)]
Punerea corect n coresponden a baiilor ocupai de o structur de tip articol cu cmpurile acesteia, mai ales n cazul n
care exist diferene generate de alocarea neoptimizat a memoriei i de apariia variabilelor k, permite interpretarea riguroas a
coninutului fiecrui cmp. Problematica devine cu att mai important cu ct variabilele de tip articol se utilizeaz pentru
partiionarea memoriei alocate unor buffere utilizate n operaii de intrare/ieire.
Noptimizarea prelucrrilor este benefic cu condiia ca interpretarea grupului de baii s fie controlat de
programator, chiar dac citirea lor are un alt ablon dect cel utilizat la scriere.
4.3. Vectori de structuri i structuri de vectori
Vectorii de structurii sunt masive omogene, n sensul c fiecare element al masivului nu difer de cellalt,
chiar dac n alctuirea lor intr cmpuri de naturi diferite.
Construcia:
typedef struct student
{
char nume[30];
int vrsta;
char facult[20];
int an_studiu;
};
student x[20];
definete un vector x avnd 20 de componente; fiecare component este un articol ce conine cmpurile nume, facult, an_studiu.
Modelul grafic al acestui tip de dat derivat este:
x este un masiv unidimensional omogen, pentru c toate cele 20 de componente au aceeai structur.
Referirea vrstei corespunztoare studentului al cincisprezecelea dintr-o grup se realizeaz prin:
x[14].vrsta
n cazul n care cmpurile unui articol sunt elemente ale unui masiv unidimensional, definim o structur de vectori. De exemplu:
typedef struct student
{
char nume[30];
int note[10];
};
xxx
x[0] xx x[1] xx x[2] xx x[14] xx x[19] xx
nume nn vrsta vv facult ff an_studiu aa nume nn vrsta vv facult ff an_studiu aa
07441A 00
R
000
07441A 00
15 11
Or OO
07441A 00
R
ooo
07441A 0000
ref(x) rr
student x;
Dac dorim s cunoatem nota a 4-a a studentului x, referirea se efectueaz prin:
x.nota[3]
Se definesc vectori de structuri ce conin vectori (vectori de structuri de vectori ) :
stud y[20];
Pentru a referi nota a 5-a a studentului al 17-lea se face referirea:
y[16].nota[4]
Lucrurile iau amploare dac se definesc structuri de matrice i matrice de structuri.
Astfel, dac ntr-o secie sunt 20 de muncitori i ntreprinderea are 30 de secii i pentru fiecare muncitor trebuie
cunoscut: timpul lucrat, salariul orar, numele, definind:
typedef struct muncitor
{
char nume[20];
long int salariu;
int ore;
};
long int salariu_total;
muncitor muncit[30][20];
putem calcula salariul total pentru muncitorul 15 din secia a 4-a astfel:
salariu_total: = muncit[3][14].salariu*muncit[3][14].ore;
Dac matricea este privit ca vectori de vectori, extensiile sunt fcute pentru masivele tridimensionale ca vectori de
matrice sau matrice de vectori, iar pentru masivele cu patru dimensiuni, ca masive bidimensionale de masive bidimensionale, sau
vectori de masive tridimensionale sau masive tridimensionale de vectori.
Generalizrile decurg din posibilitatea de a construi structuri de structuri i uneori de a introduce aspectul recursiv al
descrierii.
typedef int a[5];
typedef a b[5];
b c[5];
corespunde descrieriii
int c[5][5][5];
iar
typedef int x[5][5];
x y[5][5];
corespunde descrierii:
int z [5][5][5][5];
i referirea elementelor se efectueaz dup aceleai reguli, specificnd valori (expresii) ntre paranteze ptrate , n numr egal cu
dimensiunea atribuit masivului, ca de exemplul:
c[i][j][k]
y[i][j][k][h]
Atributele sunt comutative n raport cu operatorul de referire. Un element din vectorul de structur se refer prin:
nume_vector[i].nume_membru
iar un element din structura de vectori se refer prin:
nume_structur.nume_membru[i]
Programatorul trebuie s realizeze un echilibru ntre creterea numrului de dimensiuni, reducerea gradului de umplere
i complexitatea expresiilor asociate calculelor de deplasare, pentru a localiza fiecare element al structurii pe care o definete.
Acest echilibru conduce n final la reducerea duratei de prelucrare i la obinerea lizibilitii bune a programului.
5. VARIABILE POINTER
5.1. Tipul variabilei pointer
Pentru programatorii care cunosc un limbaj de asamblare, definirea i utilizarea variabilelor pointer n limbaje
evoluate de programare, reprezint operanzii necesari implementrii adresrii indirecte.
La adresarea indirect se utilizeaz doi operanzi i anume: operandul care refer i operandul referit, notai n
continuare R0 si respectiv Or.
07441A 00
R
000
07441A 00
15 11
Or OO
07441A 00
R
ooo
07441A 000000
ref(x) rr
adr(x) aa
Operandul Ro conine adresa de nceput a zonei de memorie asociat operandului Or. Evaluarea expresiilor:
R0 = adr(Or)
Or = 1 5
conduce la modificarea coninutului operandului Ro i a operandului Or astfel:
Deci :
cont(R0) = adr (Or)
Aceast ecuaie arat c operandul Ro este de un nou tip, Tp, ale crui valori aparin intervalului [Ai, Af] N,
unde Ai i Af sunt adrese de nceput i, respectiv, de sfrit ale unui segment de memorie.
Dac:
f(cont(R0),Tp) = TRUE,
adic
cont (R0) [Ai, Af] N
se spune ca opernadul R0 este de tipul Tp.
n continuare acest nou tip de dat este numit tipul pointer.
Funcia lg(R0,TP). definete o astfel de mrime care s permit stocarea complet a informaiei necesare localizrii operanzilor,
ale cror adrese se ncarc n variabila Ro.
Expresia:
cont(Ro) = adr(Ro)
are semnificaia ncrcrii n operandul Ro a propriei adrese.Dup evaluarea expresiei, coninutul lui Ro este:
n sine, expresia nu are o semnificaie deosebit, mai mult ofer
riscul nchiderii unui lan de referire, transformndu-l n ciclu infinit. Dac ns operandul Ro devine reper i toate deplasrile sunt
evaluate avndu-l ca baz, expresia de mai sus se justific.
Dac se definesc variabilele a,b,c avnd tipul Ti, i variabilele pa, pb, pe avnd tipul Tp, evaluarea expresiilor:
pa = adr(a)
pb = adr(b)
pe =adr(c)
realizeaz iniializarea operanzilor de tip Tp.
Dac lum n considerare aceste expresii n loc de:
c = a+b;
vom utiliza expresia:
ref(pc) = ref(pa)+ref(pb)
unde funcia de referire ref(), este definit:
ref : [Ai, Af] -> I
unde mulimea este interpretat drept coninutul zonei de memorie asociate identificatorilor.
Observm c prin definirea funciei adr()
adr : I-> [Ai, Af]
funciile adr() i ref() nu sunt una invers celeilalte. Este adevrat numai egalitatea:
x = ref(adr(x))
07441A 00
R
000
07441A 00
15 11
Or OO
07441A 00
R
ooo
07441A 000000
ref(x) rr
adr(x) aa
Nu n toate cazurile, limbajele de programare implementeaz aceast proprietate.
Proprietile funciilor sunt discutate n contextul alocrii statice a memoriei, fr posibilitatea redefinirii sau
suprapunerii de operanzi, obinndu-se zone de memorie comune pentru seturi de operanzi.
Deci, n contextul prefixat, pentru doi operanzi diferii, xi i xj de acelai tip sau de tipuri diferite.
adr(xi) adr(xj)
ref(adr(xi)) ref(adr(xj))
pentru c xi xj, din definiie.
Variabilele de tip Tp apar n expresii aritmetice, relaionale sau de atribuire, nu ca elemente n sine ci ca parametri
ai funciei ref().
Revenind la limbajul de asamblare, operaiile de calcul sunt specializate pe tipuri de operanzi. Exist operator de adunare
pentru operanzi de tip ntreg, dar exist i operator de adunare pentru operanzi de tip virgul mobil simpl precizie. Pentru
operanzii de tip dubl precizie, exist operator distinct de cei menionai.
Tot astfel, operatorii de comparare privesc zone de memorie de lungimi diferite, care s acopere totalitatea lungimilor
asociate tipurilor fundamentale de date implementate n limbajele de asamblare.
Apariia operanzilor de tip Tp, determin pierderea informaiei referitoare la tipul iniial al operandului i exist
posibilitatea generrii unei evaluri ambigue a expresiilor.
n, acest sens tipul Tp se definete ca un tip compus
Tp = (pointer,Ti)
unde Ti, reprezint tipul variabilei referite i pointer este tipul specific, fundamental al variabilei. Dac variabila care refer px,
este de tip Tp i variabila referit x, este de tip Ti, n vorbirea curent, expresia (pointer) se interpreteaz, pornind de la efectul
fizic al operaiilor cu pointeri, ca pointer spre Ti.
Dac x are tipul integer i px este de tip Tp, se spune c px este pointer spre integer i toi operatorii din expresiile omogene
ca tip de date unde apare px, sunt selectai pentru lucrul cu operanzi de tip integer.
Tipul variabilei referite nu influeneaz lungimea variabilelor de tip Tp i coninutul.
Dac o variabila x, este definit ca avnd tipul Ti i variabila px este definit ca avnd tipul (pointer,Tj ), expresia:
px = adr(x)
nu este evaluat dect numai dup ce ara loc conversia de la tipul Ti la tipul Tj, operatorul de atribuire necesitnd operanzi de acelai
tip. Aceast conversie realizeaz de fapt schimbarea setului de informaii n concordan cu operandul din stnga.
Prin conversie, adresa este asociat unei variabile de tip Tj cu toate implicaiile ce decurg asupra alinierilor i lungimii
zonelor de memorie asociate noului tip, asociat zonei de memoria pus n coresponden cu variabila x.
Exist situaii n care conversia de tip este implicit (n cazul evalurii expresiilor aritmetice), dar sunt numeroase
cazurile n care aceasta trebuie specificat explicit.
Funcia conv(x, Tj) modific tipul variabilei x de la Ti la Tj.
Dac:
tip(x) = Ti
x = conv(x,Tj)
conduce la
tip(x) = Tj
i n mod corespunztor:
px = convp(adr(x),Tj).
unde convp() reprezint funcia de conversie a tipului spre care pointeaz o variabila de tip Tp.
Expresia din dreapta conduce mai nti prin evaluarea lui adr(x) la tipul (pointer,Ti), ca mai apoi prin folosirea funciei
convp(), s se obin conversia de tip i rezultatul evalurii este (pointer,Tj), care este omogen n raport cu tipul Tp al variabilei
px.
Funcia convp() are rolul de a modifica al doilea termen al perechii (pointer,Ti) care definete tipul Tp.
Conversiile de tip, sunt facilitai cu importante efecte asupra performanei programelor, cu condiia ca e1e s se afle strict
sub controlul programatorului.
Atunci cnd conversiile de tip depesc simplele expresii de atribuire, prin crearea de noi vecinti pentru oparanzi prin
redistribuirea baiilor, sunt interpretate componente care altfel rmneau neexplorate n program. Toate ns, e necesar s fie sub
controlul programatorului. Altfel, dintr-o facilitate, conversia de tip se transforma ntr-o problem generatoare de greuti.
5.2. Aritmetica variabilelor pointer
ntruct pentru variabilele px i py de tip Tp
cont(px) [Ai, Af] N
cont(py) [Ai, Af] N
pe mulimea [Ai, Af] N se definete operaia , astfel nct pentru
,[Ai, Af] N
=
[Ai, Af] N
Dac, de exemplu, considerm intervalul [0;64000] N, operaiile de adunare, nmulire, scdere i mprire,
nu sunt legi de compoziie intern. Prin contraexemple se dovedete c exist i astfel nct:
[0;64000] N
Aparent, nu se vorbete de o aritmetic a variabilelor pointer. Totui se construiesc expresiile cu variabile pointer, cu
condiia ca rezultatul evalurii s aparin intervalului [Ai, Af] N.
Dac se definete masivul unidimensional:
float x [10];
i px este un pointer spre ntreg, i
px = adr(x[l])
evaluarea expresiei:
px = px + 6 = adr(x[l]) + l*lg(real) = adr(x[2])
conduce la posibilitatea de a referi, elementul al doilea al vectorului x.
Dac:
px = adr(x[l0] )
i evalum expresia
px = px-24
px = adr(x[10])-4*lg(real) = adr(x[6])
n expresiile:
adr(z+k) = adr(z)+k*lg(Ti)
unde z este o variabil de tip Ti, observm c pentru variabila pz de tip Tp, care a fost iniializat prin:
pz: = adr(z);
adr(z+k) = pz + k*lg(Ti)
i pentru c tipul Tp = (pointer,Ti), expresia k*lg(Ti) este rezultatul conversiei la tipul Tp al variabilei pz, a variabilei ntregi k.
n acelai mod, se definete i operaia de scdere, n ambele cazuri apare cerina ca rezultatul evalurii expresiilor s
aparin intervalului [Ai, Af] N.
Se construiesc teoretic, expresii deosebit de complexe, n care operanzii s fie de tip Tp, dar restricia de apartenen a
rezultatului la acel interval le face inoperante.
n plus, lucrul cu adrese n zone de memorie contigue i mai ales pentru structuri de date omogene, vizeaz posibilitatea de a
genera termenii unor progresii aritmetice.
Dac variabila px de tip Tp, este iniializat prin:
px = adr(x[1]);
s = 0;
for ( i = 0 ; i < 10 ; i + + )
{
s = s + ref(px);
px = px+4;
};
variabila px, permite referirea rnd pe rnd a elementelor x[0], x[1]....,x[9] ale vectorului x.
Mai mult, definind px variabila de tip Tp n secvena:
px = adr(x);
s = 0;
pi = adr(x[0]);
do
{
s = s+ref(pi);
pi = pi+4 ;
} while (pi < = adr(x[9]));
difer foarte puin de secvenele care implementeaz structurile repetitive ntr-un limbaj de asamblare oarecare.
Ca i n limbajele de asamblare, restriciile de apartenen la domeniul [Ai;Af] N, au determinat c pentru variabilele
pointer, aritmetica s se reduc la dou operaii: incrementarea i decrementarea. Aceste operaii nseamn de fapt majorarea,
respectiv diminuarea cu o unitate, dup cum urmeaz:
adr(x+l) = adr(x) + 1*lg(Ti) = px + l*lg(Ti)
adr(x-l) = px l*lg(Ti)
Conversia de tip, determin ca unitatea s fie egal de fapt cu lungimea asociat zonei de memorie ocupat de variabilele de tip
Ti.
n cazul unor expresii complexe notate :
expr(a0 a1 ... an-1)
adr(x+expr(a0 a1 .....an-1)) = px+int(expr(a0 a1 .....an-1))*lg(Ti)
Se consider c expresia:
px+int(expr(a0 a1 .....an-1))*lg(Ti) =
este corect definit dac [Ai, Af] N
n limbajul C/C++, ncrcarea adreselor variabilelor definite n program, se efectueaz cu operatorul &.
Corespondentul C/C++ al secvenelor de mai sus este:
typedef int mat[10];
mat x = {1,2, 3,4,5, 6, 7, 8, 9, 10};
int * px;
unsigned int i, s;
{
s = 0;
for ( i = 0 ; i < 10 ; i + +)
{
px = & x[i]
s = s + ( *px );
};
cout << s;
Absena controlului asupra limitelor de variaie pentru variabilele de tip Tp, determin s devin operanzi zone
nespecifice programului, alternd n acest fel inclusiv componente ale software-lui de baz, cu consecine asupra
calitii prelucrrilor curente i chiar viitoare.
5.3. Nivele de indirectare
Apare n mod firesc ntrebarea, dac tipul Tp definit iniial (pointer, Ti), unde Ti reprezint un tip fundamental de dat,
include i perechea (pointer,Tp), tiut fiind faptul c i tipul Tp este considerat tip fundamental.
Acceptnd c o astfel de construcie este corect, se creeaz posibilitatea realizrii de pointeri spre pointeri spreTi i
a pointerilor spre pointeri spre pointeri spre Ti.
Se definesc variabilele:
int Y, x ;
int * py, *px ; // (pointer, integer);
int ** ppx; // (pointer,(pointer,integer));
prin expresiile:
x = 20;
px = adr(x);
ppx = adr(px))

se obine:
iar expresiile:
py = adr(y);
y = l6;
conduc la:
zzz
3] 33 y[ 3] yy y[ 2] yy y[ 1] yy y[ 0] yy
X
222
X
333
X
444
Expresia:
ref(y) = ref(y) + ref(ref(x));
este echivalent cu:
y = y + x ;
Programul C/C++ care evalueaz expresia este:
typedef int * pint;
int x, y : integer;
pint px,py;
pint * ppx;
{
x = 20 ;
y = 15;
px = & x;
py = & y;
ppx = &px;
*py = *py + **ppx;
cout << *py ;
};
Construcia (pointer, Tp) permite compunerea unei funcii adr() asociate nivelelor indirectate.
n definiia:
int x ;
int *px ; // (pointer, integer)
int **ppx ; // (pointer, (pointer, integer))
int ***pppx ; // (pointer, (pointer,(pointer, integer)))
i din secvena:
x = 17;
px =adr(x);
ppx = adr(px);
pppx = adr(ppx);
obinem c:
pppx - adr(adr(adr(x))) = adr
3
(x)
Numrul 3 reprezint nivelul de indirectare.
Pentru referirea unei variabile avnd nivelul 3 de indirectare, se procedeaz astfel:
ref(ref(ref(pppx))) = ref
3
(pppx)
Pentru omogenizarea operanzilor n cadrul expresiilor, este necesar ca variabilele n care tipul Tp are puterea n, s fie iniializate
cu adr () i s fie referite cu ref
n
().
Se consider:
T
1
p = (pointer,Ti)
T
2
p = (pointer, (pointer, Ti)
T
3
p = (pointer,(pointer (pointer, Ti)))
Etc.
Pentru efectuarea unor generalizri privind aritmetica ordinului n a tipului Tp este necesar definirea funciei pentru evaluarea
lungimii acestui tip. Astfel, expresii ca:
adr
k
(adr
h
(x)+i) sau adr
k
(adr
h
(x)-i)
devin interpretabile.
Aa cum pentru toate tipurile de date exist constante ce sunt atribuite i pentru tipul pointer, exist constante corespunztor definite.
Constantele pentru tipul pointer, simbolizeaz adrese absolute. Se vorbete de adres nul, se vorbete de adresa 15, sau de orice alt
adres. Dac ns un program P lansat n execuie, ocup zona de memorie delimitat prin [Ai
p
, Af
p
] N, iniializarea oricrei variabile pointer,
este efectuat cu valori cuprinse n acest interval. Folosirea valorii nule are numai scop de jalonare la iniializare, pentru a vedea dac s-au
fcut atribuiri ulterioare pentru a lucra corect, sau atribuirile nu au fost posibil s se efectueze i deci nu se lucreaz pentru c variabila
pointer are valoare nul.
n programele C/C++, referirea unei variabile pointer px cu 5 nivele de indirectare, de exemplu, se realizeaz prin evaluarea
expresiei:
*****Px;
zzz
3] 33 y[ 3] yy y[ 2] yy y[ 1] yy y[ 0] yy
X
222
X
333
X
444
iar pentru valoarea nul a variabilei pointer, se folosete constanta simbolic NULL. Iniializarea unei variabile pointer cu o
adres absolut de memorie se realizeaz cu funcia Ptr(), avnd ca parametru o adres n hexazecimal; de exemplu:
py : = Ptr($00AA,$0020);
5.4. Vectori i matrice de pointeri
i cu tipul Tp se construiesc structuri de date omogene, dac toate componentele acestora au tipul Tp.
Construcia:
Tp x[n];
Tpi y[n][m];
reprezint definirea unui masiv x avnd n componente, fiecare component fiind un pointer spre Ti i, respectiv, definirea unei
matrice y avnd n linii i m coloane, elemente ce sunt pointeri spre tipul Ti.
Se justific stocarea n masive uni i bidimensionale a adreselor unor operanzi, dac acetia au diferenieri ntre ei, sau
dac tipologiile determin activri de funcii dup succesiuni stabilite.
Se memoreaz, de exemplu, mesajele unui program ce apar n dialogul cu utilizatorul, sub forma unui text continuu. Acestor
mesaje, n numr de 50, li se memoreaz adresa de nceput n componentele vectorului text[i], de pointeri spre tipul string.
Dac se dorete aflarea tuturor mesajelor prin secvena:
for (i = 0 ; i < 50 ; i + + )
cout << ref(text[i]);
se obine acelai lucru.
Dac se dorete afiarea unui anumit mesaj, este important s se cunoasc poziia n vectorul text[] a componentei n care
este memorat adresa respectivului mesaj.
Dac n cele cinci componente ale unui vector de pointeri numit px, memorm adresele primelor componente ale
vectorilor a[], b[], c[], d[], e[], cu numr de componente diferite i dorim s calculm cu funcia, suma(), suma elementelor
vectorilor, n loc s scriem de cinci ori apelul funciei suma(), scriem secvena:
for (i = 0 ; i < 5 ; i + + )
s[i] = suma(px[i], n[i]);
dac definim:
int x1[10], x2[10], x3[10], x4[10];
Tp y[4];
T
2
p z;
prin atribuirile:
y[0] = adr(xl[0]);
y[1] = adr(x2[0]);
y[2l = adr(x3[0]);
y[3] = adr(x4[0]);
z = adr(y[0]);
s-a obinut construcia cu modelul grafic:
care este identic cu modelul grafic asociat structurii de date omogene i contigue, matricea.
Tot astfel, se definete o funcie fct(), care se apeleaz prin:
fct(pl, p2, p3,, pn)
La apel, construiete un vector cu n componante n care sunt memorate adresele parametrilor reali ai funciei, deci
vectorul acesta este un vector de pointeri.
Adresa primei componente a vectorului este memorat ntr-un registru. Acest registru conine adresa listei de adrese a
parametrilor.
n cazul n care la definire funcia are parametri formali
1, 2,....., n i dac:
tip(pi) = tip(i)
i[1.2....n], nseamn c s-a obinut concordana ntre tipul parametrilor reali i tipul parametrilor formali.
zzz
3] 33 y[ 3] yy y[ 2] yy y[ 1] yy y[ 0] yy
X
222
X
333
X
444
Transmiterea parametrilor formali prin valoare, vizeaz efectuarea copierii valorilor parametrilor reali pi n zonele de
memorie definite n funcie,
asociate parametrilor i, operaie simbolizat prin expresia de atribuire:
i = pi; i = 1, 2, ...,n
n cazul n care are loc o inversare a parametrilor sau omiterea unuia dintre ei, dispare concordana de tip i tipul
parametrului i este Ti, iar tipul parametrului pi este Tj, ceea ce impune efectuarea conversiei de la tipul Tj la tipul Ti, cu toate
efectele pe care conversia de tip le antreneaz.
i = conv(pi,Ti)
determin perturbarea radical a rezultatelor.
Dac parametrii pi sunt variabile pointer n funcie, se opereaz asupra zonelor de memorie externe acesteia, a zonelor ale
cror adrese sunt conservate n variabilele pointer pi.
Aceasta explic necesitatea ca funcia de interschimb de valori s conin pointeri pentru elemente i nu elementele
nsi.
n continuare se ia n discuie programul executabil ca dat. Orice program executabil este format din instruciuni
executabile i zone de memorie ce servesc ca operanzi.
Orice program are o prim instruciune executabil i o ultim instruciune executabil. De obicei, n cazul funciilor,
prima instruciunea executabil, etichetat cu numele funciei, se numete punct de intrare n funcie. Instruciunea de apel a
funciei, efectueaz un salt necondiionat spre punctul de intrare n funcie.
Ultima instruciune executabil dintr-o funcie, este un salt necondiionat ctre programul apelator, pe baza informaiei
care localizeaz unde se efectueaz revenirea. Aceast instruciune se numete punct de ieire din program. Din punct de
vedere al structurilor de date, aceste puncte sunt de fapt elemente folclorice, care prin pitorescul lor coloreaz limbajul
programatorilor. Ca structur de date, textul executabil este un text omogen, atunci cnd toate instruciunile au o lungime i o
structur fixat. n cele mai multe cazuri, instruciunile necesit informaii care determin extensii pe cuvinte adiacente, reducnd
gradul de omogenitate a structurii de date numit program.
Totui, structura de date numit program executabil este delimitat prin dou instruciuni executabile cu aceeai
semnificaie, oricare ar fi funcia scris ntr-un limbaj evoluat. Acest lucru se datoreaz standardelor de preluare a
parametrilor i de revenire n funcia apelatoare.
Dac considerm funciile f1(), f2(), ..., fm() crora le corespund m texte program executabil, memorate n m zone de
memorie, prin fl(), f2(), ..... fm(), simbolizm adresele primelor instruciuni executabile ale acestor funcii, i dac definim punctele de
intrare ca un nou tip de dat numit tipul de date funcie, putem construi un vector de pointeri:
(pointer,funcie) pf [m];
pe care l iniializm astfel:
pf[i] = f( ); i=1,2,,m
n loc s scriem o secvena cu m apeluri de funcii, putem reduce totul la secvena:
for ( i = 0 ; i < m ; i + + )
pf [i] (p1 [i], p2 [i], ..., pn[i]);
Deci vectorul de pointeri spre funcii, faciliteaz crearea unor secvene dinamice de apel, n timpul execuiei prin
variabilitatea indicelui i.
Dac ns, funciile de intrare se memoreaz ntr-o matrice de pointeri spre funcie, avem imaginea unei mai mari diversiti
i flexibiti de prelucrare, ceea ce permite realizarea de sisteme de programe, vecine prin complexitatea lor cu sistemele de
program expert.
5.5. Variabile de tip pointer i structurile de date de tip articol
Variabilele pointer, ca de altfel orice alt tip de variabil, apar ca membri n structurile de date de tip articol. De
asemenea, o variabil pointer este definit ca pointer spre structur.
Construciile:
typedef struct a
{
int b;
Tp c;
};
b = (pointer, struct)
a x;
b y;
definesc - x ca variabil de tip articol
- y ca variabil de tip pointer spre articol
Expresiile:
y = adr(x)
ref(y).b
ref(y).c = adr(z)
ref(y) = ref(c)
reprezint modalitile de iniializare sau utilizare a membrilor structurii, n condiiile n care elementul baz de referire este o variabil pointer
i unul dintre membri este, de asemenea, tot o variabil pointer.
Deosebirea este c y este un pointer spre structura x, iar c este un pointer spre ntreg.
Lucrul cu fiiere, presupune stocarea de informaii privind caracteristicile fiierelor, precum i informaii de stare a prelucrrii
acestora. Informaiile sunt neomogene i pentru stocarea lor trebuie definite structuri corespunztoare, care se
constituie de fapt ca un vector de structur. Numrul de componente ale vectorului, indic numrul maxim de fiiere cu care se
lucreaz ntr-un program.
Acest vector de structur se pune n coresponden cu elementele ce se definesc n programele utilizatorilor.
Tipul de date FILE este de tip pointer spre o structur i caracterul local sau global acordat variabilelor de acest tip, permite definirea
zonei program din care programatorul are acces prin operaii de intrare/ieire la fiier. Programatorul are acces la fiiere prin structurile de
date de tip FILE.
Numeroi parametri ai funciilor de lucru cu fiiere, sunt pointeri care au acelai tip cu membrii structurii de date FILE, parametri care
permit iniializri de membri, sau comparri care valideaz efectuarea de operaii.
Dac fiierul nsui este pus n coresponden cu un pointer spre FILE, acest pointer apare ca parametru ntr-o funcie, ceea ce ofer
caracter general aplicaiilor. Cnd se spune c fiierul apare ca parametru ntr-o funcie, realitatea este c pointerul variabil pointer spre
structura de tip FILE, care conine descrierea fiierului cu care se dorete s se lucreze n funcie, se transmite ca parametru real.
Observm c toate informaiile despre toate entitile, date, programe i fiiere, se structureaz adecvat i devin resurse la
dispoziia programatorului.
Limbajele evoluate, precum C i C++, sunt puternice prin multitudinea funciilor de bibliotec pe care programatorii le apeleaz.
Numeroase funcii necesit, definirea unor variabile n programe, de un tip derivat, definit ca global n fiiere, ce trebuie incluse n program.
Programatorul trebuie s cunoasc aceste structuri, pentru a putea folosi informaiile pe care la returneaz funciile apelate.
Funciile, primesc ca parametrii reali variabile elementare, sau masive, sau structuri, sau pointeri. sau alte tipuri derivate i/sau
definite global.
Funciile returneaz valori ce se stocheaz n variabile elementare, n structuri de tip articol, n date de tip pointer. Numrul
valorilor returnate este unu. Pentru a obine ca funcia s returneze un masiv, uni sau bidimensional, e suficient ca acesta s fie
inclus ntr-o structur de tip articol.
Programatorul care face distincie ntre toate tipurile de date prezentate pn acum i care e deprins s vehiculeze uor
definirile i referirile acestora, prin funcii de bibliotec sau funcii proprii are acces la absolut toate resursele unui sistem de calcul.
Se observa c:
- referirea unei variabile elementare se face prin nume ;
- referirea unui masiv se face prin nume, iar al unui element al su prin nume urmat de o expresie indicial cuprins ntre [];
- referirea unei structuri de tip articol se face prin nume, iar a unui membru indicnd numele structurii separat de operatorul punct,
de numele membrului respectiv;
- referirea unei date de tip pointer se face prin nume, iar a variabilei a crui adres o conine, printr-un operator de
referire;
- referirea unui fiier se efectueaz prin numele variabilei pointer spre tipul de date FILE; iniializarea i utilizarea
acestei structuri este la dispoziia funciilor destinate lucrului cu fiiere.
Comparnd referirile, observm c pentru a defini aceste tipuri de date sunt necesare informaii care s indice tipul i
ordinea pe care componentele o au n cadrul structurilor ca entiti efective, desfurate liniar i contiguu n memorie.
5.6. Definirea i utilizarea variabilelor pointer n limbajul C
n limbajul C, pentru tipul pointer, prin declaraia tip * nume, se prelucreaz tipul.
De exemplu:
int * px, * py ;
int x,y ;
Pentru iniilizarea variabilelor pointer, se folosete operatorul &.
De exemplu:
px = & x;
py = & y;
Funciei de referire i corespunde operatorul *.
Dac x este1 i y este 2, expresia:
*px = *px + *py;
este echivalent cu:
x = x+y;
i are corespondent n consideraiile anterioare:
ref (px) = ref (px) + ref (py)
n cazul definirii pointerilor spre tipuri de date derivate, se folosesc construcii precum:
typedef struct b
{
int c;
int d;
int e;
int * g;
};
typedef b *a;
a x;
b y;
Expresiile:
x = &(y);
x-> c: = 3
x-> d: = x-> c*5;
x-> e: = 1
x-> g: = Addr(x^,e);
x-> e: = x-> e +x-> g;
ilustreaz modaliti de referire a membrilor unei structuri.
n cazul definirii:
typedef int c;
typedef c * b;
typedef b * a;
a x;
b y;
c z;

expresiile:
z = 7;
y = &(z);
x = &(y);
cout << **x
ilustreaz modaliti de lucru cu pointeri spre ntreg (variabila y) i cu pointeri spre ntreg(variabila x).
Funciei ref
k
(px) i corespunde construcia **de k ori***px
Iar funciei adr
k
(px), i corespunde secvena:
p1 = &(x);
p2 = &(p1);
.
pk = &(pk-1);
instruciunile:
int * px;
int x;

px = &(x);
x = 7;
cout << *px
au acelai efect ca cout << x;
Aplicaiile complexe, necesit definirea de vectori de pointeri spre matrice, pointeri spre vectori de pointeri spre pointeri
spre matrice, pointeri spre vectori de pointeri.
Programele de mai jos, realizeaz sumele elementelor a trei matrice, folosind diferite modaliti de referire a elementelor,
specificate la fiecare program prin comentariu.
{vectori de pointeri spre matrice}
#include <iostream.h>
typedef int mat[2][3];
typedef mat * pmat;
typedef pmat vecp[3];
vecp vp;
int i,j,k;
int s[3] = {0,0,0};
mat a = {1,1,1,2,2,2};
mat b = {3,3,3,4,4,4};
mat c = {5,5,5,6,6,6};
main()
{
vp[0] = &a;
vp[1] = &b;
vp[2] = &c;
for (k=0 ; k<3 ; k++)
{
for (i=0 ; i<2 ; i++)
for (j=0 ; j<3 ; j++)
s[k]=s[k]+ (*vp[k])[i][j];
cout<<"\n Suma matricei "<<k<<" este "<<s[k];
}
}
{vectori de pointeri spre pointeri la o matrice}
#include <iostream.h>
typedef int mat[2][3];
typedef mat * pmat;
typedef pmat vecp[3];
typedef pmat* vecpp[3];
vecp vp;
vecpp vpp;
int i,j,k;
int s[3] = {0,0,0};
mat a = {1,1,1,2,2,2};
mat b = {3,3,3,4,4,4};
mat c = {5,5,5,6,6,6};
main()
{
vp[0] = &a;
vp[1] = &b;
vp[2] = &c;
for (i=0 ; i<3 ; i++)
vpp[i] = &vp[i];
for (k=0 ; k<3 ; k++)
{
for (i=0 ; i<2 ; i++)
for (j=0 ; j<3 ; j++)
s[k]=s[k] + (**vpp[k])[i][j];
cout<<"\n Suma matricei "<<k<<" este "<<s[k];
}
}
{pointeri spre vectori de pointeri}
#include <iostream.h>
typedef int vec[5];
typedef int * vecp[5];
typedef vecp *pvec;
int * ppp;
vec a = {1,2,3,4,5};
vecp p;
pvec pp;
int i;
main()
{
for (i=0 ; i<5 ; i++)
p[i] = &a[i];
01A880 00
cod_material cc
cod_grup cc cod_subgrup cc
0100A0 00
ppp = a;
pp = &p;
for (i=0 ; i<5 ; i++)
{
cout<<"\n"<<*(ppp+i)<<" ** "<<(*p[i]);
cout<<"\n"<<(*(*pp)[i]);
}
}
{pointeri spre vectori de pointeri spre pointeri la matrice}
#include <iostream.h>
typedef int mat[2][3];
typedef mat * pmat;
typedef pmat vecp[3];
typedef pmat* vecpp[3];
typedef vecpp * pvecpp;
vecp vp;
vecpp vpp;
pvecpp pvpp;
int i,j,k;
int s[3] = {0,0,0};
mat a = {1,1,1,2,2,2};
mat b = {3,3,3,4,4,4};
mat c = {5,5,5,6,6,6};
main()
{
vp[0] = &a;
vp[1] = &b;
vp[2] = &c;
for (i=0 ; i<3 ; i++)
vpp[i] = &vp[i];
pvpp = &vpp;
for (k=0 ; k<3 ; k++)
{
for (i=0 ; i<2 ; i++)
for (j=0 ; j<3 ; j++)
s[k]=s[k]+ (**(*pvpp)[k])[i][j];
cout<<"\n Suma matricei "<<k<<" este "<<s[k];
}
}
Un exemplu de program n care sunt puse n eviden modaliti de referire a unor structuri complexe, este considerat
urmtorul:
#include <iostream.h>
typedef int vec[5];
typedef int * pvec[5];
typedef pvec * ppvec;
typedef struct strz
{
vec aa;
pvec paa;
ppvec pppa;
};
typedef strz * pstr;
typedef pstr ps[2];
typedef ps* pps;
int i,j;
01A880 00
cod_material cc
cod_grup cc cod_subgrup cc
0100A0 00
0100A0 00
A [1, 1] AA
01 AA00 00
B [ 1, 1] BB
U [1] UU
01 BB00 00
V[1] VV
01 BB00 00
X [1] XX
CCC
strz st[2];
ps pst;
pps pss;
main()
{
st[0].aa[0] = 100;
st[0].aa[1] = 200;
st[0].paa[0] = &st[0].aa[0];
st[0].paa[1] = &st[0].aa[1];
st[1].aa[0] = 300;
st[1].aa[1] = 400;
st[1].paa[0] = &st[1].aa[0];
st[1].paa[1] = &st[1].aa[1];
pst[0] = &st[0];
pst[1] = &st[1];
pss = &pst;
st[0].pppa = &st[0].paa;
st[1].pppa = &st[1].paa;

for (i = 0 ; i < 2 ; i++)
for (j = 0 ; j < 2 ; j++)
{
cout<<"\n*"<<st[i].aa[j]<<"**"<<*(pst[i]->paa[j]);
cout<<"++"<<*((*pss)[i]->paa[j])<<"--"<<*((*pss)[i]->pppa[j]);
}
}
6. REUNIUNILE DE DATE CONTIGUE
6.1. Necesitatea restructurrii datelor.
n multe aplicaii codul materialului este privit ca ntreg, iar n cazul verificrii cifrelor de control, fiecare element sau
grupuri de elemente sunt privite ca formate din cmpuri de 1 bait.
n primul i al doilea caz, zona de memorie asociat codului de material este fi reprezentat prin dou modele grafice i
anume:
Observm c ambele structuri ocup aceeai zon de memorie, al crui nceput este marcat de baitul cu adresa 01A880.
O alt situaie corespunde prelucrrii articolelor dintr-un fiier. Pentru o aplicaie sunt necesare primele cinci cmpuri,
pentru o alt aplicaie sunt necesare apte cmpuri din interiorul articolului, iar pentru a treia aplicaie sunt necesare ultimele patru
cmpuri. Pentru toate aplicaiile, primul cmp este necesar ntruct servete drept cmp de regsire a informaiilor.
Modelul grafic al zonei de memorie astfel structurat este:
01A880 00
cod_material cc
cod_grup cc cod_subgrup cc
0100A0 00
0100A0 00
A [1, 1] AA
01 AA00 00
B [ 1, 1] BB
U [1] UU
01 BB00 00
V[1] VV
01 BB00 00
X [1] XX
CCC
01 CC00 00
DDD
Cele trei structuri care se suprapun peste aceeai zon de memorie, presupun lungimi identice i o aceeai adres de
nceput.
n acest caz, rezult c zona de memorie este mai nti definit pentru precizarea uneia dintre structuri, iar celelalte
structuri care se suprapun, apar ca redefiniri ale zonei de memorie.
Atunci cnd se definete un masiv tridimensional a, cu 10x10x10 elemente i un alt masiv b, unidimensional cu 1000
elemente, tipul lor fiind unic, dac se procedeaz la punerea n coresponden a elementelor a[1][1][1] i b[1], n sensul
adr ( a[1][1][1] ) = adr ( b[1] )
secvena
for (i = 0; i < 10; i + +)
for (j = 0; j < 10; j + +)
for (k = 0; k < 10; k + +)
a[i][j][k] = 0;
este nlocuit cu secvena:
for (i =0; i < 1000; i + +)
b[i] = 0;
care din punct de vedere a volumului operaiilor de prelucrare este mai eficient.
Exist probleme n care algoritmii de rezolvare cer definirea de masive care difer ca nume i ca dimensiuni de la o etap
la alta, dar care sunt disjuncte din punct de vedere al utilizrii coninutului.
De exemplu, pentru un algoritm alctuit din trei etape, este necesar utilizarea structurilor menionate n tabelul de mai
jos:
Structura
Etapa
A B U V C D X
Etapa 1 * * *
Etapa 2 * * *
Etapa 3 * * *
unde:
A [10][10]
B [20][20]
U [10]
V [20]
struct C {} , lg (C) = 50
struct D {} , lg (D) = 40
X [30]
Rezult c matricele A i B sunt suprapuse, vectorii U, V i X deasemenea, iar structurile de tip articol C i D, urmeaz
aceeai cale.
Cele trei suprapuneri sunt reprezentate cu modelele grafice urmtoare:
A [1, 1] AA
01 AA00 00
B [ 1, 1] BB
U [1] UU
01 BB00 00
V[1] VV
01 BB00 00
X [1] XX
CCC
01 CC00 00
DDD
a
000
a
111
b
000
b
111
b
222
b
333
b
444
xxx
6.2. Funcia de reunire
Se consider datele d1, d2, d3,...,dn, avnd tipurile T1, T2, ..., Tn i m1, m2,...,mn membrii de referin ai acestora.
n continuare un membru al unei structuri de date este numit de referin, dac n raport cu el sunt puse n eviden. Se
definete funcia:
union: T1*T2...*Tn(TRUE, FALSE)
i
union (m1, m2,...,mn) = TRUE
dac i numai dac:
adr(m1) = adr(m2) = adr(mn) =
[Ai, Af] N
Se noteaz:
} (mi) adr | (di) {adr min
n i 1

< <
i
} (mi) adr | Ti) ( lg (di) adr { max
n i 1
+
< <
Cele n structuri de date redistribuite ca dispunere n raport cu adresa , a celor n cmpuri de referin, ocup o zon de
memorie de lungime

+ 1 baiti.
Diferitele limbaje de programare impun restricii precum:
} } (mi) adr | (di) adr { min Ai, { max
n i 1

< <
a
000
a
111
b
000
b
111
b
222
b
333
b
444
xxx
i
111
i
22222222222 i
333
i
4444444444444 i
555
ceea ce determin existena unui minim control asupra adresei operanzilor, n sensul c adresele acestora s nu ias n afara
domeniului prefixat n limitele Ai i Af.
Dac se consider o dat de baz, de exemplu d1,
union (m1, m2,...,mn) = TRUE
dac:

'

>

n ..., 3, 2, i (d1) adr (di) adr
n ..., 2, 1, i (mi) adr
De exemplu, acest grup de restricii se regsete n limbajul FORTRAN.
Se consider masivele definite prin:
int a[10];
int b[5];
i structura:
struct k
{
int x;
char g[10];
};
k t;
i datele elementare:
int x, y;
Funcia:
union (a [3], b [5], g, x, y )
conduce la modelul grafic de suprapunere urmtor:
adr ( a [3] ) = adr ( b [5] ) = adr ( t*g) = adr (x) = adr (y) =
Adresa de nceput pentru fiecare din cele cinci cmpuri, se obine:
adr (a [3] ) = adr (a [0] ) + 3*1g (int)
adr (a [0] ) = - 3*1g (int)
adr (b [0] ) = - 5*1g (int)
adr ( g ) = - 1*1g (int)
adr ( x ) =
adr ( y ) =
n programele C/C++, exist posibilitatea realizrii reuniunii de date folosind atributul absolute. De exemplu:
int x[3][3];
y : array [1 .. 9] of integer absolute x;
efectueaz punerea n coresponden:
adr (x [1][1] = adr (y [1] ), adr (x [1][2] ) = adr (y [2] ),
adr (x [1][3] = adr (y [3] ), adr (x [2][1] ) = adr (y [4] ),
adr (x [2][2] = adr (y [5] ), adr (x [2][3] ) = adr (y [6] ),
adr (x [3][1] = adr (y [7] ), adr (x [3][2] ) = adr (y [8] ),
adr (x [3][3] = adr (y [9] ).
a
000
a
111
b
000
b
111
b
222
b
333
b
444
a
3
g
0
g
1
g
2
.......
..
g
8
g
9
xxx
y
i
111
i'
111
i'
222
i
22222
i'
333333333
i'
444
i
333
i
4444444
i'
555555555
i
555
6.3. Reuniunea ca rezultat al iniializrii variabilelor pointer.
n condiiile construirii de tipuri de date derivate, nu se efectueaz alocare de zone de memorie. Prin definirea de pointeri
p1, p2, ..., pn spre tipurile de date derivate, odat cu construirea modelului grafic al reuniunii de date, se evalueaz adresa ca fiind
adresa de nceput a unei variabile dk, din lista d1, d2, ..., dn.
} (di) adr { min (dk) adr
n i 1 < <

cu condiia ca:
adr(m1) = adr(m2) = ... = adr(mn)
Se calculeaz deplasrile:
Di = depl(di, dk)
cu Di > 0 pentru i = 1, 2, ..., n.
Prin evaluarea expresiei:
Di ) Ti , ( convp Pi +
se obine adresa de nceput a fiecrei date din tipul Ti, aa nct:
adr(m1) = adr(m2) = ... adr(mn) = adr(d1) + depl(m1, d1).
Mecanismele de implementare prin pointeri a reuniunii de structuri de date, este util mai ales n cazul structurilor de
date contigue, a cror alocare se efectueaz dinamic.
Chiar dac iniial, funciile de reuniune sunt definite cu unele restricii asupra alinierii, la stnga sau la dreapta a
elementelor, printr-o aritmetic adecvat de evaluare a expresiilor n care apar variabile pointer, aceste restricii sunt eliminate.
Reuniunile de date, n multe cazuri sunt rezultatul unor prelucrri accidentale i n depanarea programelor e necesar
identificarea modulului n care s-au fcut suprapunerile unor date peste altele.
6.4. Zonele de memorie tampon gazde ale reuniunilor de date contigue.
Prelucrarea datelor n condiiile scderii intensitii pe care resursa memorie o impune ca restricie, revine la a defini
zone de memorie n care se citesc date din fiiere, uneori chiar fiierele integral, pentru a fi prelucrate ca date existente numai n
memoria intern a calculatorului.
n acest context, memoria tampon (bufferul) este pus n coresponden cu structuri de tip articol i pri ale sale sunt
interpretate, sau intr ca operanzi n expresii, sub forma membrilor de structur.
Cazul cel mai frecvent corespunde situaiei n care, pentru orice structur de date din irul ordonat d1, d2, ... dn avem:
union( mi, mj ) = FALSE
adr(di+1) = adr(di) + lg(di)
1 n ..., 2, 1, i ) (
, adic datele sunt disjuncte.
n cazul lucrului cu buffere, se caut ca prin aritmetica de pointeri s se obin aceea suprapunere care coincide, fie cu
modul n care a fost creat fiierul, fie cu obiectivul urmrit.
Dac programul de creare a fiierului conine ca definire structura dk, iar programul de exploatare a fiierului conin aceeai
structur d

k, cu deosebirea c
lg(dk) = lg(d'k).
ceea ce conduce la concluzia c cele dou structuri sunt numai asemntoare prin numrul identic de cmpuri i coincidena
tipurilor, dar difer prin lungimile a dou cmpuri corespondente.
S presupune c:
lg(dk) - lg(d'k) = 1
Dup n citiri de nregistrri d

k din fiierul creat cu nregistrri avnd structura dk, se obine o diferen de n baii pn la a n + 1
nregistrare corect plasat n fiier.
i
111
i'
111
i'
222
i
22222
i'
333333333
i'
444
i
333
i
4444444
i'
555555555
i
555
Decalajul de 1 bait genereaz o suprapunere dinamic, distana ntre nceputul nregistrrii ik i nregistrarea i'k se mrete
pe msur ce indicele k crete, fiind de k-1 baii.
Problema depistrii cauzelor de obinere a rezultatelor eronate, crete n complexitate dac diferena
lg(dk) lg(d'k) > 1
Este necesar n aceste cazuri, s se defineasc funcii de verificare a concordanei dintre parametrii ce caracterizeaz o
structur.
De asemenea, n cazul n care din punct de vedere al tipurilor pe care le au datele elementare, care intr n componena
articolelor sau a masivelor, reunirile apar ca suprapuneri de tipuri, omogene sau nu, cu toate consecinele ce decurg.
Astfel, o dat elementar sau atom, este definit din punct de vedere al tipului ca:
E = (Ti)
unde Ti, este unul din tipurile fundamentale T1, T2,..., Tn, n fiind numrul de tipuri fundamentale implementate n limbajul de
programare considerat.
Masivul unidimensional, se definete ca tip vector Tv astfel:
Tv = (Ti, Ti, ..., Ti)
Numrul de componente coincide cu dimensiunea vectorului i tipul este acelai pentru toate elementele.
O matrice este fi cu tipul Tm, definit:
Tm = (Tv, Tv ..., Tv)
O structur de tip articol, are tipul:
Ta = (Ti1, Ti2, ..., Tim)
unde,
} Ta Tm, Tv, Tn, ..., T2, T1, { Tik
O structur de vectori, este definit prin:
Tsv = (Tv, Tv ..., Tv)
Un vector de structur, se definete prin:
Tvs = (Ta, Ta ..., Ta)
Deplasnd problematica reuniunii de date la nivelul reuniunii de date ca tipuri, obinem o nou interpretare i anume:
) T ..., , T , union(T
n 2 1
x x x
= TRUE
dac exist cel puin un
i
k
T

i
x
T
, astfel nct oricare ar fi dou elemente de tip
i
x
T
i
j
x
T
s existe:
) tkj ( tadr ) Tki ( tadr

unde,
i
k
T
reprezint tipul membrului cu poziia k din tipul derivat
i
x
T
.
n acest context, tadr(
i
k
T
) reprezint o mulime a adreselor operanzilor de tip
i
k
T
ai structurii de tip derivat
i
x
T
.
Considerm spre exemplificare structurile:

struct a
{
char e[20];
int a;
float c;
};
i
struct x
{
int y;
char z[4];
float u;
int w;
};
Structura de tip
Ta = ( char[], int, float, bool)
iar structura de tip
Tx = ( int, char[], float, int)
union (Ta, Tx) se evalueaz astfel:
- se definesc mulimile:
} (w) adr , (y) adr { ) Tbint ( tadr
} (a) adr { ) Taint ( tadr

tadr ( ) este funcia de extragere a adreselor elementelor de un tip specificat dintr-o structur.
) bool Tx ( tadr
} (d) adr { ) bool Ta ( tadr
} (z) adr { ) char[] Tx ( tadr
} (e) adr { ) char[] Ta ( tadr
} (u) adr { ) float Tx ( tadr
} (c) adr { ) float Ta ( tadr

Presupunem c programatorul are la dispoziie posibilitatea de a modifica coninutul contorului de locaii, n aa fel nct
s realizeze o definire a structurilor a i b nct:
) real Tx ( tadr ) boolean Ta ( tadr
deci,
) T , T ( union
x a
= TRUE
Implementrile curente genereaz cazuri particulare n care:
) j x ( adr ) i x ( adr
unde x

i, x

j sunt membrii cu poziia 1 din structurile i i j.


Membrii care alctuiesc o structur dintr-o reuniune de structuri, au adresa calculat fa de primul membru al structurii.
Toi primii membrii ai structurilor, au aceeai adres.
Privind structurile de date ca structuri de tipuri,
) i x ( adr ) j x ( adr ) T2i ( tadr ) T1i ( tadr
pentru oricare i i j, ce corespund tipurilor de date derivate ce definesc structurile considerate.
O astfel de abordare mrete generalitatea modelului asociat reuniunii de structuri, ntruct nu mai sunt luate n calcul
direct lungimile efective ale operanzilor de un anumit tip, lungimi ce difer de la un mod de implementare al unui limbaj, la alt
limbaj.
Mai mult, aplicarea funciei union la suprapunerile accidentale a structurilor, prin considerarea tipurilor ca entiti de
baz, permite descifrarea rezultatelor, care numai aparent au caracter nedeterminat.
De exemplu, programele de mai jos evideniaz modaliti de realizare a reunirilor de date. Primul program, uniune 1
iniializeaz o zon sub forma unui masiv unidimensional pe care o utilizeaz ca masiv bidimensional la afiare.
// program uniune 1;
union reuniune
{
int a[3][3];
int b[9];
}z;
int i, j;
main()
{
for ( i = 0 ; i < 9 ; i++ )
z.b[i] = i * i;
for ( i = 0 ; i < 3 ; i++ )
{
for ( j = 0 ; j < 3 ; j++ )
cout<<"\n "<<z.a[i][j];
}
}
Programul uniune 2, definete n cadrul unor structuri de tip STRUCT, cmpuri pe care le reunete la aceeai adres de
memorie, efectund exploatarea diferenial a acesteia.
//program uniune 2:
#include <string.h>
#include <iostream.h>
struct union1
{
char x[10];
};
struct union2
{
char y[5];
};
struct union3
{
char z[10];
a
000 a
111
a
222
a
333
a
444
a
555
a
666 a
777
a
888
a
999
. . . ..
b
000
b
111
b
222
b
888
b
999
};
union uniune2
{
union1 un1;
union2 un2;
union3 un3;
}u2;
main()
{
strcpy(u2.un1.x,"1234567890");
cout<<u2.un1.x;
cout<<"\n";
for(int i=0;i<5;i++)
u2.un2.y[i]='a'+i;
for(i=0;i<5;i++)
cout<<u2.un2.y[i];
cout<<"\n"<<u2.un1.x;
cout<<"\n";
for(i=0;i<15;i++)
cout<<u2.un3.z[i];
}
7. LISTELE STRUCTURI DINAMICE NECONTIGUE
7.1. Structuri de date dinamice necontigue.
Structurile de date statice, sunt acelea care se definesc n program i n faz de compilare se calculeaz deplasri pentru
fiecare cmp elementar sau grup de cmpuri, astfel nct dup editarea de legturi, orice evaluare de adres s permit referirea
corect a structurilor sau a componentelor lor.
Caracterul local sau global al variabilelor, conduce la o abordare diferenial a variabilelor statice. Chiar variabilele care
se definesc n cadrul unui bloc i care au caracter local, a cror alocare de memorie i iniializare, este realizat prin mecanisme
proprii mediului de programare care implementeaz limbajul , n continuare sunt tratate tot ca structuri sau funcii apelate la cerere
de ctre programatori.
n continuare, se grupeaz sub denumirea de structuri dinamice, acele structuri pentru care alocarea i dealocarea
memoriei este gestionat de programator.
Funciile care aloc memorie au ca parametrii, acele informaii care conduc la rspunsuri neabigue la ntrebrile:
- care este lungimea zonei de memorie care se aloc?
- unde este stocat adresa zonei de memorie alocat, pentru a fi la dispoziia programatorului?
- se iniializeaz zona de memorie alocat nainte de a fi utilizat de programator?
Mecanismul de alocare dinamic a memoriei, are la baz faptul c n memoria intern a unui sistem de calcul, apare o zon
disponibil delimitat prin
N ] Df Di, [
, unde: Di este adresa de nceput a zonei
Df este adresa de sfrit a zonei
La intrarea n execuie a programului, un registru RO, sau o zon de memorie fixat, se iniializeaz cu valoarea Di.
Dac ntr-un program este activat funcia de alocare definit prin:
y = alocare (lg (Ti) )
i
alocare:
N. ] Df Di, [ N
Ti pointer, ( ) y ( tip unde ), RO ( cont y
)
RO = RO + lg ( Ti )
Dac:
cont ( RO ) > Df y = 0
Dac ntr-un program este activat funcia de dealocare a memoriei:
z = dealocare ( y ).
RO = RO lg ( Ti )
a
000 a
111
a
222
a
333
a
444
a
555
a
666 a
777
a
888
a
999
. . . ..
b
000
b
111
b
222
b
888
b
999
i n cazul alocrii, dac:
tip (y) = (pointer, Tj)
i variabila x din
alocare (lg (x) )
are tipul Ti, se impune efectuarea unei conversii de tip.
Astfel,
) ) ) x ( alocare ( tip , ) y tip( ( convtp y
unde, convtp( ) este o funcie de conversie a tipului de data Tp.
Algoritmii de structurare a memoriei n pagini i ,modul n care se face ncarcarea programelor, precum i momentele
uneori aleatoare din program la care se apeleaz funciile de alocare/dealocare, conduc n cele mai multe cazuri, ca pentru dou
apelri consecutive ale funciei de alocare, zonele alocate s fie necontigue.
Necesitatea definirii n programe a datelor de tip dinamic, este dat de utilizarea mai bun a memoriei, lungimea unui
program variind n funcie de volumul datelor cu care se lucreaz.
n programe C/C++, pentru alocarea dinamic de memorie, se apeleaz procedura new( ), iar pentru dealocare, procedura
free( ) sau delete( ). Ca argument, procedura new( ) are tipul de dat pentru care se face alocarea zonei de memorie, iar free( ) i
delete( ) au o variabil pointer, care indic adresa zonei ce se elibereaz.
Se consider un program P pentru calculul inversei unei matrice. Pentru a-i oferi o mai larg aplicabilitate, se consider
c acest program este definit aa fel nct, s poat inversa matrice cu cel mult 50 linii i 50 coloane.
Definirea static a matricei:
int a[50][50];
determin ocuparea unei zone de 2500 * lg (int) baii.
Deci:
) executabil text ( lg ) baiti ( lg * 2500 ) P ( lg + +
unde, reprezint lungimea total a zonei de memorie rezervat altor variabile de control sau de lucru.
Indiferent de problema de rezolvat, lg( P ) = constant.
Se tie c n lucru multiuser, un factor care influeneaz ateptarea ntr-un fir, nainte de intrarea n prelucrare, este i
lungimea programului.
n contextul definirii matricei ca operand alocat dinamic, la execuia de fiecare dat a programului, se introduce
dimensiunea matricei de inversat, folosind variabila n de tip ntreg.
Lungimea programului pentru rezolvarea problemei Pi, se determin dinamic:
+ + ) executabil text ( lg (integer) lg * n ) Pi ( lg
i se are n vedere c:
lg ( Pi ) lg ( P )
tiut fiind faptul c zona la dispoziia alocrii dinamice este
N ] Df , Di [
, finit.
Restriciile impuse asupra domeniul pe care este definit funcia alocare( ), determin filozofia ntregului proces de
construire a variabilelor dinamice.
n cazul n care:
alocare :
N ] Df , Di [ Z
este creat posibilitatea efecturii de reacoperiri de zone, deci se genereaz mecanisme de realizare a uniunii de structuri dinamice
de date.
De exemplu, se consider structurile:
int a[10];
int b[10];
i variabilele pa i pb de tip Tp = (pointer, int), prin:
pa = alocare (10 * lg (int) )
pb = alocare (7 * lg (int) )
pb = alocare (-3 * lg (int) )
se obinute reuniunea cu modelul grafic:
n cele mai multe cazuri, modul de definire al funciilor de alocare este limitativ, dar reuniunea este totui posibil
prin aritmetica variabilelor pointer, care se iniializeaz cu aceste funcii.
Structurile de date formate din elementele omogene E1, E2, ..., Em, de un tip derivat sau fundamental TE, se numesc
necontigue, dac exist cel puin o pereche (Ei, Ei+1) astfel nct:
adr( Ei+1 ) > adr( Ei ) + lg(TE)
i dac:
adr( Ei+1 ) = adr( Ei ) + lg(TE) + i
a
000 a
111
a
222
a
333
a
444
a
555
a
666 a
777
a
888
a
999
. . . ..
b
000
b
111
b
222
b
888
b
999
01788 A 00
pg pp
New(pg) NN
iii
jjj
val vv
01788 A 00
018800 00
poz pp
iii
jjj
val vv
018800 00
Z
jjj
Z
j+1

New (pn) NN
NULL NN ... ..
pg->poz = pn; pp
pg->poz = pg; pp
... ..
unde e o variabil aleatoare, de regul uniform distribuit. Pentru a avea acces la elementele E1, E2, ..., Em, sub o form care s
permit adresarea corect a elementelor necontigue.
Exist posibilitatea prin definirea unor pointeri spre pointeri i iniializarea corespunztoare a acestora, s se procedeze la
reaezarea operanzilor alocai dinamic, n aa fel nct s dispar golurile dintre operanzi, rezultate n procesul de
alocare/dealocare.
Dac se consider constantele C1, C2, ... ,Cn avnd tipul Ti, care ocup zonele de memorie Z1, Z2, ... , Zn, i numerele
aleatoare 1, 2, , n a cror lege de distribuie, de regul uniform distribuit, se spune c mulimile de perechi (Zj, j) determin o
structur de date necontigu de tip list, dac:
succ( Zj) = Zj + 1
pred( Zj) = Zj - 1
i:
adr( Zj+1 ) = adr( Zj ) + lg(Ti) + j = j
Dac
1 = 2 = = n
atunci se obine cazul particular de dat unidimensional cu necontiguitate nul, ce corespunde masivului unidimensional contiguu
vectorul , i zona de memorie pentru conservarea variabilei i nu se mai justific, ntruct ea este calculabil ca:
j = adr( Zj ) + lg(Ti) = adr( Z1) + (j-1)*lg( Ti)
Dac se ia n considerare mecanismul alocrii dinamice a memoriei, atunci:
j = cont ( RO )
la momentul tj, ce corespunde alocrii zonei de memorie pentru perechea (Zj+1, j+1).
Privit din punct de vedere al tipului de dat, Zj reprezint informaia util, iar j reprezint informaia de identificare a
succesorului.
adr(succ( Zi )) =
Perechea ( Zj, j ) definete o structur de date de tip list, numit TL, unde j este dat de tip Tp = ( pointer, TL ).
7.2. Modelul grafic al listei ca structur necontigu
Se consider necesar ca o matrice rar s fie memorat far a se cunoate n prealabil, numrul elementelor nenule
(gradul de ncrcare) al su.
Rnd pe rnd, se introduce de la terminal linia, coloana i valoarea elementului nenul. Se aloc dinamic o zon de
memorie pentru stocarea acestor elemente, precum i un cmp pentru stocarea adresei zonei n care se stocheaz elementul
urmtor.
struct zona
{
int i;
int j;
float val;
zona *poz;
};
typedef zona * pa;
Folosind succesiv apelarea procedurii:
pg = new( zona );
unde, pg este o variabil de tip pa, iar pa la rndul ei este un pointer spre structura zona, se aloc o zon de memorie de adresa
cont (RO) i lungime lg (Tzona), ce este referit folosind variabila pointer pg, care este de tipul Tp = (pointer, Tzona).
n program, membrii structurii se refer prin:
pg->i
pg->j
pg->val
Dac pn, este variabil de tip pa i se apeleaz funcia pn = new(zona), variabila pn conine adresa zonei n care este
stocat urmtorul element al matricei rare.
Atribuirea:
pg->poz = pn
este echivalent cu:
j = adr(succ( Zj ))
01788 A 00
pg pp
New(pg) NN
iii
jjj
val vv
01788 A 00
018800 00
poz pp
iii
jjj
val vv
018800 00
Z
jjj
Z
j+1

New (pn) NN
NULL NN ... ..
Z
k-1 kk

kkk
Z
kkk

k+1 kk
Z
k+1 kk

k+2 kk
.... ..
Z
k-1 kk

k+1 kk
Z
kkk

k+1 kk
Z
k+1 kk

k+2 kk
.... ..
pg->poz = pn; pp
pg->poz = pg; pp
... ..
pg->poz = pn;
Dac:
succ( Zn) =
atunci:
adr( succ( Zn)) = NULL
pg->poz->poz = NULL;
Acest algoritm de construire a irului 1, 2, , n conduce la modelul grafic:
O astfel de list se numete list liniar simplu nlnuit.
ncrcarea matricei rare se face exact cu attea elemente cte valori nenule se afl pe linii i coloane. Spre deosebire de
cazul n care se foloseau 3 vectori pentru stocarea informaiilor, acum nu mai exist restricii legate de rezervrile predefinite ale
celor 3 vectori.
Totul depinde de modul n care programul solicit spaii din zon
N ] Df Di, [
i mai ales de dimensiunile
proiectate ale acestei zone la generarea sistemului de operare.
Dac n loc de:
adr( succ( Zn)) = NULL
se construiete:
adr( succ( Zn)) = adr( Z1)
lista se numete circular i n <> NULL.
Pentru transformarea listei care stocheaz matricea rar n list circular, la terminarea prelucrrii.
pn->poz = pg;
unde, pg stocheaz adresa zonei de memorie alocat pentru primul element nenul al matricei rare.
Modelul grafic al listei circulare este:
Lungimea listei liniare:

1 i
] ) i Zi, ( [ lg L
i <> NULL
unde, lg[Zi, NULL] = 0.
7.3. Operaii cu liste liniare simplu nlnuite
Parcurgerea listei liniare simplu nlnuite corespunde funciei de extragere a adresei elementului succesor i de referire a
membrilor acestuia.
Pentru tiprirea coninutului elementelor matricei rare, cu numr necunoscut de elemente nenule, funcia de parcurgere,
construit recursiv este:
01788 A 00
pg pp
New(pg) NN
iii
jjj
val vv
01788 A 00
018800 00
poz pp
iii
jjj
val vv
018800 00
Z
jjj
Z
j+1

New (pn) NN
NULL NN ... ..
Z
k-1 kk

kkk
Z
kkk

k+1 kk
Z
k+1 kk

k+2 kk
.... ..
Z
k-1 kk

k+1 kk
Z
kkk

k+1 kk
Z
k+1 kk

k+2 kk
.... ..
( Z
1
,
1
))) ( Z
2
,
2
))) ( Z
3
,
3
))) ( Z
n
,
n
)))
( U
1
,
1
))) ( U
2
,
2
))) ( U
3
,
3
))) ( U
m
,
m
)))
NULL NN


... ..
... ..
pg->poz = pn; pp
pg->poz = pg; pp
... ..
parcurgere ( pg )
{
while (pg->poz != NULL)
{
tiprete (pg->i, pg->j, pg->val)
parcurgere (pg->poz)
}
}
Considernd lista ca mulimea de perechi de forma (Z, ) de tip TL.
w = adr( Z1 )
conine adresele de regsire a elementelor listei.
parcurgere ( adr ( w ) )
{
while (w != NULL)
{
tiprete ( w, z );
parcurgere ( ref ( w ), )
}
}
tergerea unui element ( Zk, k) al listei.
nainte de tergere lista este:
Dup efectuarea tergerii:
tergere ( w, w1, Zk )
{
while (ref (w). != NULL || ref (w).Z != Zk)
{
w1 = ref (w, );
tergere (w1, w, Zk)
}
if ref (w1).Z = Zk
ref (w). = ref (w1).
}
Concatenarea a dou liste (Z, ) i (U, ), reprezint ca ultimul element al primei liste s-i schimbe valoarea din NULL
a lui n cu adresa elementului (U1, 1).
Deci,
ref( Zn ). n = adr[ (U1, 1)]
Funcia care efectueaz concatenarea listelor este:
concatenare
] ) U, ( , ] ) Z, ( [
{
while (ref ( Z ) . != NULL)
{
concatenare ( ( ref ( Z ) . , ) , ( U, Z ) )
}
ref ( Z ). = adr ( ( U, ) )
Z
k-1 kk

kkk
Z
kkk

k+1 kk
Z
k+1 kk

k+2 kk
.... ..
Z
k-1 kk

k+1 kk
Z
kkk

k+1 kk
Z
k+1 kk

k+2 kk
.... ..
( Z
1
,
1
))) ( Z
2
,
2
))) ( Z
3
,
3
))) ( Z
n
,
n
)))
( U
1
,
1
))) ( U
2
,
2
))) ( U
3
,
3
))) ( U
m
,
m
)))
NULL NN


... ..
... ..
}
Modelul grafic al concatenrii:
Lista concatenat are ca prin element ( Z1, 1 ), iar ca ultim element (Um, m).
Fizic, lista ( U, ) nu s-a modificat. Conservnd adr(Z, 1) i (U, 1) se lucreaz cu cele 2 liste, ca i cum concatenarea
nu s-a executat. Totui lista concatenat, pentru operaia de parcurgere se comport ca o list cu m+n componente.
Modificarea unui element al listei
Fie lista (Zi, i), i = 1, 2, ... ,n
Pentru nlocuirea unei valori a cu valoarea b, trebuie mai nti gsit elementul k pentru care,
cont (Zk) = a,
dup care se realizeaz atribuirea Zk = b;
n toate cazurile (parcurgere, tergere, concatenare, modificare), disciplina de parcurgere este de la primul element ctre
ultimul primul venit primul servit ( First In First Out).
modificare (w)
{
if (ref (w). z != a)
modificare (ref (w). )
else
ref (w). z = b
}
Copierea unei liste
Fie lista (Zj, j), j = 1, 2, ... ,n.
Se pune problema obinerii unei liste
(Z

j,

j), j = 1, 2, ... ,n.


astfel nct
cont(Z

j) = cont(Zj)
pentru j = 1, 2, ... ,n
copiere_lista (w, u)
{
while (ref (w). != NULL)
{
ref (u). Z = ref (w). Z
alocare (v)
ref (u). = v
copiere_lista (ref (w).), v)
}
ref (u). = NULL
}
( Z
1
,
1
))) ( Z
2
,
2
))) ( Z
3
,
3
))) ( Z
n
,
n
)))
( U
1
,
1
))) ( U
2
,
2
))) ( U
3
,
3
))) ( U
m
,
m
)))
NULL NN


... ..
... ..
... ..
(Z
k
,
k
))) (Z
k+1
,
k+1
)))
... ..
(, )))
aaa
... ..
(Z
k
, adr()) )) (Z
k+1
,
k+1
)))
... ..
(, adr (Z
k+1
)) ))
aaa
(Z
1
,
1
))) (Z
n
, adr( )) ,,
... .. ... ..
NULL NN
(,adr ( Z
1
)))
bbb
(, )))
bbb
(Z
k-1
,
k-1
))) (Z
k
,
k
))) (Z
k+1
,
k+1
)))
... .. ... ..
... .. ... .. NULL NN
(,
)))
aaa
(,
)))
aaa
Inserarea unui element n list
Se spune c o list este ordonat cresctor dac:
) 1 Zj ( cont ) Zj ( cont +
pentru orice
1. - n ..., 2, 1, j
A insera un element ntr-o list, nseamn mai nti a gsi o valoare
} n ..., 2, 1, { k
astfel nct:
) 1 Zk ( cont a ) Zk ( cont +
sau
) 1 Zk ( cont a ) Zk ( cont +
dup cum lista este ordonat cresctor sau descresctor. n aceste condiii, inserarea elementului a, nseamn conform modelului
grafic, a trece de la configuraia:
... ..
(Z
k
,
k
))) (Z
k+1
,
k+1
)))
... ..
(, )))
aaa
... ..
(Z
k
, adr()) )) (Z
k+1
,
k+1
)))
... ..
(, adr (Z
k+1
)) ))
aaa
(Z
1
,
1
))) (Z
n
, adr( )) ,,
... .. ... ..
NULL NN
(,adr ( Z
1
)))
bbb
(, )))
bbb
(Z
k-1
,
k-1
))) (Z
k
,
k
))) (Z
k+1
,
k+1
)))
... .. ... ..
(Z
j-1
,
j-1
))) (Z
j
,
j
))) (Z
j+1
,
j+1
)))
... .. ... ..
(Z
k-1
,
k-1
)))
(Z
k
,
k
))) (Z
k+1
,
k+1
)))
... .. ... ..
(Z
j-1
,
j-1
)))
(Z
j
,
j
)))
(Z
j+1
,
j+1
)))
... .. ... ..
... .. ... .. NULL NN
(,
)))
aaa
(,
)))
aaa
la configuraia:
Exist cazuri particulare de inserare, n care elementul este poziionat fie la nceputul listei, fie la sfritul acesteia, cazuri
n care operaia se numete adugare.
Dac elementele a i b vor fi inserate la nceputul, respectiv, la sfritul listei, se trece de la configuraia:
la configuraia:
Interschimbul ntre dou elemente ale listei
Interschimbul nu se realizeaz fizic, zonele ce corespund celor dou elemente modificndu-i doar adresele de referire a
elementelor.
Modelul grafic al listei nainte de interschimbul elementelor (Zk, k) i (Zj, j) este:
... ..
(Z
k
,
k
))) (Z
k+1
,
k+1
)))
... ..
(, )))
aaa
... ..
(Z
k
, adr()) )) (Z
k+1
,
k+1
)))
... ..
(, adr (Z
k+1
)) ))
aaa
(Z
1
,
1
) (Z
n
,
n
)
(Z
1
,
1
))) (Z
n
, adr( )) ,,
... .. ... ..
NULL NN
(,adr ( Z
1
)))
bbb
(, )))
bbb
(Z
k-1
,
k-1
))) (Z
k
,
k
))) (Z
k+1
,
k+1
)))
... .. ... ..
(Z
j-1
,
j-1
))) (Z
j
,
j
))) (Z
j+1
,
j+1
)))
... .. ... ..
(Z
k-1
,
k-1
)))
(Z
k
,
k
))) (Z
k+1
,
k+1
)))
... .. ... ..
(Z
j-1
,
j-1
)))
(Z
j
,
j
)))
(Z
j+1
,
j+1
)))
... .. ... ..
... .. ... .. NULL NN
(,
)))
aaa
(,
)))
aaa
Dup efectuarea interschimbului, legturile dintre componente sunt:
Funcia pentru efectuarea interschimbului, realizeaz atribuirile:
k-1 = adr( Zj )
j-1 = adr( Zk )
j = adr( Zk+1 )
k = adr( Zj+1 )
ceea ce nseamn c la un moment dat sunt gestionate ase adrese de variabile de tip TL, ale elementelor ce se interschimb,
precum i a elementelor adiacente.
Sortarea elementelor unei liste
Fiind dat o structur de date de tip list (Zj, j), j = 1, 2, ..., n, funcia de sortare transform aceast structur de date ntr-
o nou list (Zk, k), k = 1, 2, ..., n astfel nct oricrui
N ] n 1, [ k
i corespunde un
N ] n 1, [ j
i numai unul aa
nct,
cont( Zk ) = cont( Zj )
i
) 1 Zk ( cont ) k Z ( cont +
pentru orice
1 - n ..., 2, 1, k
.
Funcia de sortare apeleaz la rndul ei funcia de interschimb a dou elemente adiacente, pn cnd n final se obine
ordinea cresctoare sau descresctoare a termenilor Zi din lista iniial.
Un exemplu simplu de sortare, fr a lua n considerare multitudinea de tehnici este:
sortare (w)
{
k = 1
while (k != 0)
{
k = 0
while (ref (w). != NULL)
{
if (ref (w).Z > ref (w).ref (). Z)
{
k = 1
interschimb (w, w.)
}
{iniializri pointeri pentru testul urmtor}
}
}
}
(Z
k-1
,
k-1
)))
(Z
k
,
k
))) (Z
k+1
,
k+1
)))
... .. ... ..
(Z
j-1
,
j-1
)))
(Z
j
,
j
)))
(Z
j+1
,
j+1
)))
... .. ... ..
... ..
(Z
j-1
,
j-1
,
j-1
))) (Z
j
,
j
,
j
) (Z
j+1
,
j+1
,
j+1
)))
... ..
... .. ... ..
(Z
1
,
1
,
1
))) (Z
2
,
2
,
2
) (Z
n-1
,
n-1
, n-1) nn
... ..
(Z
n
,
n
,
n
)))
Un exemplu de program care calculeaz valoarea total a stocurilor de materiale constituite ntr-o list cu afiarea
acestora, este urmtorul:
//PROGRAM liste:
#include <iostream.h>
#include <malloc.h>
struct elem_lista
{
int cant;
int pret;
elem_lista * p_adr_urm_elem;
};
typedef elem_lista * p_lista;
p_lista p_lista_creata;
int val, n;
p_lista constr_lista(int nr_elem)
{
p_lista p_element_nou ;
int cant1, pret1;
if ( nr_elem == 0) return NULL;
else
{
nr_elem = nr_elem - 1;
cout<<" cantitate : ";
cin>>cant1;
cout<<" pret : ";
cin>>pret1;
p_element_nou = new (elem_lista);
p_element_nou->cant = cant1;
p_element_nou->pret = pret1;
p_element_nou->p_adr_urm_elem = constr_lista(nr_elem);
return p_element_nou;
}
};
int calcul_valoare( p_lista p_inceput_lista )
{
int valoare ;
valoare = 0;
while ( p_inceput_lista != NULL)
{
cout<<"\n cantitate din lista : "<<p_inceput_lista->cant;
valoare = valoare + p_inceput_lista->cant *
p_inceput_lista->pret;
p_inceput_lista = p_inceput_lista->p_adr_urm_elem;
};
return valoare;
};
main()
{
cout<<" numarul de elemente in lista este : ";
cin>>n;
p_lista_creata = constr_lista (n);
val = calcul_valoare (p_lista_creata);
cout<<"\n valoarea este : "<<val;
}
... ..
(Z
j-1
,
j-1
,
j-1
))) (Z
j
,
j
,
j
) (Z
j+1
,
j+1
,
j+1
)))
... ..
... .. ... ..
(Z
1
,
1
,
1
))) (Z
2
,
2
,
2
) (Z
n-1
,
n-1
, n-1) nn
... ..
(Z
n
,
n
,
n
)))
7.4. Liste dublu nlnuite
Spre deosebire de listele simplu nlnuite care permit parcurgerea de la primul element spre ultimul alocat dinamic,
listele dublu nlnuite realizeaz i drumul invers, permind i parcurgerea de la ultimul element ctre primul element.
Modelul grafic al listei dublu nlnuite este:
sau:
Lista dublu nlnuit este de fapt format din dou liste ( Zj, j ) i ( Uj, j ) cu proprietile:
) 1 j ( cont ) 1 j ( cont
) 1 Zj ( adr ) j Zj, ( cont
) 1 Zj ( adr ) j Zj, ( cont
) j ( lg ) j ( adr ) j ( adr
) Uj ( cont ) Zj ( cont ) Uj ( adr ) Zj ( adr
+

+
+


i cu listele dublu nlnuite se efectueaz operaii precum:
- inserarea unui element;
- adugarea unui element;
- tergerea unui element;
- inversarea a dou elemente;
- tergerea listei;
- parcurgerea ntr-un sens i n sensul opus;
- transformarea listei n list circular dublu nlnuit.
Un exemplu de creare, iniializare, parcurgere a unei liste dublu nlnuite, este urmtorul program:
//PROGRAM dliste:
#include <iostream.h>
#include <malloc.h>
struct dlista
{
int x;
dlista * prec, *purm;
};
typedef dlista * pdlista;
... ..
(Z
j-1
,
j-1
,
j-1
))) (Z
j
,
j
,
j
) (Z
j+1
,
j+1
,
j+1
)))
... ..
... .. ... ..
(Z
1
,
1
,
1
))) (Z
2
,
2
,
2
) (Z
n-1
,
n-1
, n-1) nn
... ..
(Z
n
,
n
,
n
)))
void scrie( pdlista pp, int i)
{
while (pp != NULL)
{
cout<<"\n"<<pp->x;
if (i==0) pp = pp->purm;
else pp = pp->prec;
}
}
pdlista p1,p2,p3,p4,pw;
main()
{
p1 = new (dlista); p2 = new (dlista);
p3 = new (dlista); p4 = new (dlista);
p1->x = 3; p2->x = 5; p3->x = 11; p4->x = 21;
p1->prec = NULL; p1->purm = p2;
p2->prec = p1; p2->purm = p3;
p3->prec = p2; p3->purm = p4;
p4->prec = p3; p4->purm = NULL;
pw = p1;
scrie(pw,0);
pw = p4;
scrie(pw,1);
p2->purm = p4;
p4->prec = p2;
pw = p1;
scrie(pw,0);
pw = p4;
scrie(pw,1);
}
Un alt exemplu de lucru cu liste dublu nlnuite, folosind funcii recursive pentru afiarea elementelor, este urmtorul program:
//PROGRAM lista dubla:
#include <iostream.h>
#include <malloc.h>
struct dlista
{
int val1,val2;
dlista * p_anterior, *p_urmator;
};
int x[5] = {1,10,100,1000,10000};
int y[5] = {20000,2000,200,20,2};
typedef dlista * pdlista;
pdlista pprecedent, pcurent, purmator, ppp_pr, ppp_ur;
int i;
void tipareste_lista_dubla( pdlista ppreced,pdlista ppurmat)
{
while (ppreced != NULL)
{
cout<<"\n"<<ppreced->val1;
tipareste_lista_dubla(ppreced->p_urmator,ppurmat);
return;
}
while (ppurmat != NULL)
{
[ a, b ] [[
[a , ]
a + b aa
222
( , b ]
a + b aa
222
cout<<"\n"<<ppurmat->val2;
tipareste_lista_dubla(ppreced,ppurmat->p_anterior);
return;
}
}
main()
{
pprecedent = new (dlista);
ppp_pr = pprecedent;
pprecedent->p_anterior = NULL;
pprecedent->val1 = x[0];
pprecedent->val2 = y[0];
for( i=1; i<5; i++ )
{
pcurent = new (dlista);
pprecedent->p_urmator = pcurent;
pcurent->val1 = x[i];
pcurent->val2 = y[i];
pcurent->p_anterior = pprecedent;
pprecedent = pcurent;
}
pcurent->p_urmator = NULL;
ppp_ur = pcurent;
tipareste_lista_dubla(ppp_pr, ppp_ur);
}
Pentru tergerea unui element dintr-o list dublu nlnuit, mai nti acesta trebuie reperat, dup care se efectueaz
modificarea legturilor i eliberarea zonei de memorie corespunztoare elementului ters;
//PROGRAM lista dubla cautare:
#include <iostream.h>
#include <malloc.h>
struct dlista
{
int val1,val2;
dlista * p_anterior, *p_urmator;
};
int x[5] = {1,10,100,1000,10000};
int y[5] = {20000,2000,200,20,2};
typedef dlista * pdlista;
pdlista pprecedent, pcurent, purmator, ppp_pr, ppp_ur, pelem;
int i;
void tipareste_lista_dubla( pdlista ppreced,pdlista ppurmat)
{
while (ppreced != NULL)
{
cout<<"\n"<<ppreced->val1;
tipareste_lista_dubla(ppreced->p_urmator,ppurmat);
return;
}
while (ppurmat != NULL)
{
cout<<"\n"<<ppurmat->val2;
tipareste_lista_dubla(ppreced,ppurmat->p_anterior);
return;
}
}
[ a, b ] [[
[a , ]
a + b aa
222
( , b ]
a + b aa
222
[a , ]
3a + b 33
444
( , ]
3a + b 33
444
a + b aa
222
( , ]
a + b aa
222
a + 3b aa
444
( , b ]
a + 3b aa
444
( a + b + c +d ) * ( x y ) ((
c d cc
e = ee
eee
ddd
ccc
***
xxx
yyy
+++
+++
ccc
ddd
+++
aaa
bbb
***
biblioteca
1xxxxx : 7xxxxx 11
matematica
1xxxxx : 23xxxx 11
calculatoare
24xxxx : 51xxxx 22
economie
52xxxx : 7xxxxx 55
algebra geometrie
1xxxxx / 198xxx /
197xxx 23xxxx 11
hardware software
24xxxx / 420xxx /
419xxx 51xxxx 44
teorie software
52xxxx / 681xxx /
680xxx 7xxxxx 66
pdlista cauta_elem(pdlista ppreced, int wval)
{
pdlista pp;
while( ppreced->val1 != wval)
{
ppreced = ppreced->p_urmator;
}
return ppreced;
}
void sterge_elem( pdlista ppreced)
{
ppreced->p_anterior->p_urmator = ppreced->p_urmator;
ppreced->p_urmator->p_anterior = ppreced->p_anterior;
cout<<"ssss";
free(ppreced);
}
main()
{
pprecedent = new (dlista);
ppp_pr = pprecedent;
pprecedent->p_anterior = NULL;
pprecedent->val1 = x[0];
pprecedent->val2 = y[0];
for( i=1; i<5; i++ )
{
pcurent = new (dlista);
pprecedent->p_urmator = pcurent;
pcurent->val1 = x[i];
pcurent->val2 = y[i];
pcurent->p_anterior = pprecedent;
pprecedent = pcurent;
}
pcurent->p_urmator = NULL;
ppp_ur = pcurent;
tipareste_lista_dubla(ppp_pr, ppp_ur);
pelem = cauta_elem(ppp_pr,100);
cout<<"\nuuuu"<<pelem->val1;
sterge_elem(pelem);
tipareste_lista_dubla(ppp_pr,ppp_ur);
}
9. ARBORI BINARI
9.1. Structura de date de tip arborescent
Gsirea soluiei ecuaiei
] b a, [ pentru x 0 ) x ( f
se efectueaz cu metode de calcul numeric, dintre care cea mai
simpl este aceea a njumtirii intervalului.
Se calculeaz:
2 / ) b a ( c +
Dac:
0 ) c ( f * ) a ( f <
,
nseamn c rdcina
) c a, [ x
, n caz contrar
] b (c, x
.
Noul subinterval este i el divizat. Astfel, avem imaginea unei modaliti de lucru ierarhizat pe attea nivele cte sunt
necesare obinerii unei precizii pentru soluia ecuaiei
0 ) x ( f
.
Asociem acestor nivele reprezentarea grafic:
[ a, b ] [[
[a , ]
a + b aa
222
( , b ]
a + b aa
222
[a , ]
3a + b 33
444
( , ]
3a + b 33
444
a + b aa
222
( , ]
a + b aa
222
a + 3b aa
444
( , b ]
a + 3b aa
444
( a + b + c +d ) * ( x y ) ((
c d cc
e = ee
eee
ddd
ccc
***
xxx
yyy
+++
+++
ccc
ddd
+++
aaa
bbb
***
biblioteca
1xxxxx : 7xxxxx 11
matematica
1xxxxx : 23xxxx 11
calculatoare
24xxxx : 51xxxx 22
economie
52xxxx : 7xxxxx 55
algebra geometrie
1xxxxx / 198xxx /
197xxx 23xxxx 11
hardware software
24xxxx / 420xxx /
419xxx 51xxxx 44
teorie software
52xxxx / 681xxx /
680xxx 7xxxxx 66
Z
j- j 111
Z
jjjjj jjjjjj
Zj + 1 ZZ
===
+++
ccc
+++
aaa bbb
eee
+++
=== null nn
eee null nn
ccc null nn +++
Evaluarea expresiei aritmetice:
prin modul de efectuare a calculelor conduce la reprezentarea:
Pentru regsirea crilor ntr-o bibliotec, n fiierul tematic cotele se structureaz pe nivele, ca n exemplu:
Reprezentarea n memorie a informaiilor care au multiple legturi ntre ele, trebuie s fie astfel fcut, nct s poat
realiza parcurgerea complet a zonelor sau localizarea unui element din structur.
( a + b + c +d ) * ( x y ) ((
c d cc
e = ee
eee
ddd
ccc
***
xxx
yyy
+++
+++
ccc
ddd
+++
aaa
bbb
***
biblioteca
1xxxxx : 7xxxxx 11
matematica
1xxxxx : 23xxxx 11
calculatoare
24xxxx : 51xxxx 22
economie
52xxxx : 7xxxxx 55
algebra geometrie
1xxxxx / 198xxx /
197xxx 23xxxx 11
hardware software
24xxxx / 420xxx /
419xxx 51xxxx 44
teorie software
52xxxx / 681xxx /
680xxx 7xxxxx 66
Z
j- j 111
Z
jjjjj jjjjjj
Zj + 1 ZZ
===
+++
ccc
+++
aaa bbb
eee
+++
=== null nn
eee null nn
ccc null nn +++
aaa null nn bbb null nn
AAA
BBB CCC
DDD
EEE FFF GGG
Observm c, n arborescen exist un nod numit rdcin sau printe. Acesta are descendeni. Fiecare descendent poate
fi la rndul su printe i n acest caz are descendeni.
Arborele binar este caracterizat prin aceea c, orice nod al su are un singur printe i maxim doi descendeni. Fiecare
nod este reprezentat prin trei informaii i anume:
Z informaia util care face obiectul prelucrrii, ea descriind elementul sau fenomenul asociat nodului;

- informaia care localizeaz nodul printe;

- informaia (informaiile) care localizeaz nodul (nodurile) descendent (descendente).


Alocarea dinamic determin ca

s fie variabile aleatoare, ale cror legi de repartiie sunt necunoscute. Valorile
lor sunt stocate n zona de memorie, formnd mpreun cu variabila Z structura de date asociat unui nod, structur ce corespunde
tripletului (Zj,

j,

j) asociat nodului j dintr-un graf de form arborescent binar.


Volumul informaiilor destinate localizrii nodurilor, depinde de obiectivele urmrite i de rapiditatea cu care se dorete
localizarea unui anumit nod. Cu ct diversitatea prelucrrilor este mai mare, cu att se impune stocarea mai multor informaii de
localizare.
Dac tripletul (Zj,

j,

j) ce corespunde modelului grafic:


permite baleierea de sus n jos, sau de jos n sus, pe o ramur a arborelui. Pentru a parcurge pe orizontal arborele, este necesar
att o informaie suplimentar de localizare
j
, ce corepunde nodului vecin din dreapta de pe acelai nivel, ct i informaia
j

pentru localizarea nodului din stnga de pe acelai nivel.
Un astfel de arbore se descrie prin:
) j j, j, j, Zj, (
Descrierea complet a unui arbore, presupune crearea mulimii tripletelor sau cvintuplelor asociate nodurilor.
De exemplu, arborescenei asociate evalurii expresiei:
e = a + b + c;
i corespunde alocarea i iniializarea zonelor de memorie:
Z
j- j 111
Z
jjjjj jjjjjj
Zj + 1 ZZ
1) (Zj adr j
1) - (Zj adr j
+

===
+++
ccc
+++
aaa bbb
eee
+++
=== null nn
eee null nn
ccc null nn +++
aaa null nn bbb null nn
AAA
BBB CCC
DDD
EEE FFF GGG
Acestor reprezentri grafice, trebuie s le corespund algoritmi pentru ncrcarea adreselor, ntruct a construi forma
liniarizat a structurii arborescente, nseamn n primul rnd, a aloca zone de memorie i n al doilea rnd, a iniializa membrii
structurii cu adrese care s permit reconstruirea corect a nlnuirii.
Observm c pentru iniializarea corect, este necesar existena la un moment dat a pointerilor spre trei zone de
memorie alocate dinamic i anume:
pp poiterul spre zona alocat nodului precedent (printe);
pc pointerul spre zona asociat nodului curent;
pd poiterul spre zona asociat primului descendent;
Construirea nodului
) j j, Zj, (
revine la efectuarea iniializrilor:
(pd); new
pd; pc
pc; pp
pd; j . (pc) ref
pp; j . (pc) ref
citita; valoare_ j Z . (pc) ref

Dup efectuare secvenei se face trecerea la pasul urmtor.


Folosind simbolurile, orice structur arborescent se reprezint prin:
N mulimea nodurilor
A mulimea arcelor
De exemplu, arborescena dat pentru calculul expresiei:
e = a + b + c;
se reprezint prin:
N = { e , = , a, + ,b + ,c }
i
A = { (a+) , (b+) , (c+) , (+, =) , (=, e) }
Observm c pentru fiecare element al mulimii {N}, se aloc dinamic zona de memorie ce conine i informaiile
j j,
. La alocare este posibil numai iniializarea zonei Zj.
Odat cu alocarea se iniializeaz i un vector de pointeri, cu adresele ce corespund zonelor de memorie puse n
coresponden cu nodurile.
n continuare, prelund elementele mulimii {A}, are loc completarea cmpurilor
j i j
.
De exemplu, pentru arborele binar:
construirea se efectueaz astfel:
a) se aloc 7 zone de memorie cu structura
) j j, Zj, (
pentru nodul din mulimea
} G F, E, D, C, B, A, { N
i se iniializeaz vectorul de pointeri pp[i] dup cum urmeaz:
(ZG) adr [7] pp
(ZF) adr [6] pp
(ZE) adr [5] pp
(ZD) adr [4] pp
(ZC) adr [3] pp
(ZB) adr [2] pp
(ZA) adr [1] pp

Baleierea mulimii:
AAA
BBB CCC DDD
eee fff ggg hhh iii jjj kkk iii
AAA
BBB xxx
eee uuu CCC DDD
fff ggg hhh yyy iii
vvv
jjj www
kkk lll
AAA
BBB CCC
DDD
EEE FFF GGG
} (CG) (CF), (BE), (BD), (AC), (AB), { A
revine la efectuarea atribuirilor:
pp[2] ). (pp[1] ref
pp[4] ). (pp[2] ref
pp[6] ). (pp[3] ref
NULL ). (pp[7] ref
). (pp[6] ref ). (pp[5] ref ). (pp[4] ref


pp[1] ). (pp[2] ref
pp[2] ). (pp[4] ref
pp[1] ). (pp[3] ref
pp[3] ). (pp[6] ref
pp[3] ). (pp[7] ref
NULL ). (pp[1] ref ). (pp[1] ref
Pentru arborii binari echilibrai, exist posibilitatea ca dup alocarea memoriei s se descrie elementele mulimii A, dup
care iniializrile cmpurilor j i j s se fac prin apelarea unei funcii. Problematica devine mai simpl, dac arborele binar
este complet, adic are n nivele la baz 2
**
(n-1) elemente descendente, fr a fi printe, noduri terminale.
n programele C/C++, pentru implementrea structurilor de date necontigue, arborele binar se definete prin urmtorul tip
de baz derivat.
struct arbore
{
int valoare;
arbore1 *precedent;
arbore1 *urmator;
};
struct arbore_oarecare
{
int valoare;
arbore_oarecare **fii; //lista fiilor unui nod
int nrfii; //nr de fii ai nodului
};
struct arbore_binar
{
int valoare;
arbore_binar *stanga;
arbore_binar *dreapta;
};
9.2. Transformarea arborilor oarecare n arbori binari
Aplicaiile concrete, asociaz unor obiecte, subansamble sau procese, structuri de tip arborescent care nu sunt binare,
astfel nct se contureaz ideea ca arborii binar sunt cazuri particulare de arbori, mai ales prin frecvena cu care sunt identificai n
practic. Mecanismele de realizare i de utilizare a arborilor binar i fac practice, dei n realitate au frecvena de apariie sczut.
Apare problema transformrii unei structuri arborescente oarecare ntr-o structur arborescent binar, problema
rezolvabil prin introducerea de noduri fictive.
Astfel, fiind dat arborescena:
AAA
BBB CCC DDD
eee fff ggg hhh iii jjj kkk iii
AAA
BBB xxx
eee uuu CCC DDD
fff ggg hhh yyy iii
vvv
jjj www
kkk lll
transformarea ei n structur arborescent binar, revine la introducerea nodurilor fictive, x, y, u, v, w;
Arborele oarecare, are un numr de noduri mai mic dect arborele binar, nodurilor fictive corespunzndu-le zone de
memorie structurate (NULL, j, j).
Alocarea dinamic presupune, ca n zona [Di, Df] prin dealocare s apar goluri, adic zone libere ce sunt realocate
altor variabile. Este necesar o gestionare a acestor zone i periodic trebuie s se efectueze o realocare prin reorganizare, aa fel
nct s dispar golurile rezultate n procesul de alocare-dealocare multipl.
De exemplu, pentru un program P, este necesar alocarea a 3 zone de memorie de 1500, 2000, 4000 baii, ce corespund
arborilor binar A, B i C.
Alocarea este efectuat iniializnd variabilele pointer pA, pB i pC prin apelul succesiv al funciei alocare ( ), (pas 1).
Dealocarea dup un timp a arborelui binar B, determin apariia unui gol ntre zonele ocupate de variabilele A i C,
(pas 2).
Alocarea unei zone de memorie pentru arborii binari D (3000 baii) i E (1000 baii), revin la a dispune pe D n
continuarea lui C i a intercala arborele E ntre A i C, n golul rezultat din dealocarea lui E, rmnnd ntre E i C un gol de
300 baii, (pas 3).
Dac se pstreaz informaiile privind modul de iniializare a variabilelor pointer care stocheaz adresele nodurilor
rdcin a arborilor A, E, C i D, este posibil glisarea informaiilor n aa fel nct s dispar golul dintre E i C. Nu s-a luat n
considerare nsi necontiguitatea din interiorul fiecrui arbore.
n practic, apare problema optimizrii dispunerii variabilelor dinamice, dar i cea a alegerii momentului n care dispersia
elementelor atinge un astfel de nivel, nct zona pentru alocare dinamic este practic inutilizabil i trebuie reorganizat.
Programul urmtor, exemplific o modalitate de creare a unui arbore binar i de tiprire a acestuia:
AAA
BBB CCC DDD
eee fff ggg hhh iii jjj kkk iii
AAA
BBB xxx
eee uuu CCC DDD
fff ggg hhh yyy iii
vvv
jjj www
kkk lll
//Program 1
#include <iostream.h>
#include <malloc.h>
struct nod
{
int val;
nod *pdrept;
nod *pstang;
};
nod *pwdrept, *pwstang, *pppp, *pwwstang, *pwwdrept, *pwradacina;
nod wnod;
int y[7]={111,112,11,121,122,12,1};
int z[7]={200,300,400,500,600,700,800};
nod * construire_nod(nod * pnodstang, nod * pnoddrept, int valoare)
{
nod *pwnod;
pwnod=new nod;
pwnod->pdrept=pnodstang;
pwnod->pstang=pnoddrept;
pwnod->val=valoare;
return pwnod;
};
nod * constr(int x[7])
{
pwstang=construire_nod(NULL, NULL, x[0]);
pwdrept=construire_nod(NULL, NULL, x[1]);
pwwstang=construire_nod(pwstang, pwdrept, x[2]);
pwstang=construire_nod(NULL, NULL, x[3]);
pwdrept=construire_nod(NULL, NULL, x[4]);
pwwdrept=construire_nod(pwstang, pwdrept, x[5]);
return(construire_nod(pwwstang, pwwdrept, x[6]));
};
nod * cautare_arbore(nod *pwnod, int wvaloare)
{
nod * pwwwnod;
if (pwnod == NULL) return NULL;
else
if (pwnod->val == wvaloare)
{
cout<<"\n"<<pwnod->val;
pppp = pwnod;
}
else
{
pwwwnod = cautare_arbore(pwnod->pstang, wvaloare);
pwwwnod = cautare_arbore(pwnod->pdrept, wvaloare);
}
return pppp;
};
main()
{
pwradacina = constr(y);
cout<<"\n radacina ="<<pwradacina->val;
pppp = cautare_arbore(pwradacina, 111);
cout<<"\n valoare ="<<pppp->val;
pppp->pdrept = constr(z);
pwwstang = cautare_arbore (pwradacina, 700);
cout<<"\n valoare ="<<pwwstang->val;
pppp = NULL;
pwwstang = cautare_arbore(pwradacina, 1000);
if (pwwstang != NULL) cout<<"\n valoare ="<<pwwstang->val;
else
cout<<"\n Element negasit !";
}
Programul de mai jos, exemplific o modalitate de copiere a unui arbore binar:
//Program 2
#include <iostream.h>
#include <malloc.h>
struct nod
{
int val;
nod *pdrept;
nod *pstang;
};
nod *pwdrept, *pwstang, *pwwstang, *pwwdrept, *pwradacina;
nod wnod;
int val;
nod * construire_nod(nod * pnodstang, nod * pnoddrept, int valoare)
{
nod *pwnod;
pwnod=new nod;
pwnod->pdrept=pnodstang;
pwnod->pstang=pnoddrept;
pwnod->val=valoare;
return pwnod;
};
void tiparire_arbore (nod *pwradacina)
{
if (pwradacina == NULL) cout<<"\n Arbore vid !";
else
{
cout<<"\n"<<pwradacina->val;
tiparire_arbore (pwradacina->pstang);
tiparire_arbore (pwradacina->pdrept);
}
};
nod * copiere_arbore (nod * pwnod)
{
if (pwnod == NULL) return NULL;
else
return construire_nod(pwnod->pstang,pwnod->pdrept, pwnod->val);
};
main()
{
pwstang = construire_nod (NULL, NULL, 111);
pwdrept = construire_nod (NULL, NULL, 112);
pwwstang = construire_nod (pwstang, pwdrept, 11);
pwstang = construire_nod (NULL, NULL, 121);
pwdrept = construire_nod (NULL, NULL, 122);
pwwdrept = construire_nod (pwstang, pwdrept, 12);
pwradacina = construire_nod (pwwstang, pwwdrept, 1);
tiparire_arbore (pwradacina);
pwstang = copiere_arbore (pwradacina);
tiparire_arbore (pwstang);
}
Arad AA
Cluj CC
Timioara TT
Craiova CC
Bucureti BB
Constana CC
59 55
324 33
274 22
331 33
209 22
497 44
225 22
AAA
BBB
CCC
DDD
Graf neorientat GG
AAA
BBB
CCC
DDD
Graf orientat GG
Programul urmtor, exemplific modaliti de traversare a nodurilor unui arbore binar, construit interactiv:
//Program 2
#include <iostream.h>
#include <malloc.h>
struct varf
{
int cod;
varf *drept;
varf *stang;
};
enum trav {preordine, inordine,postordine};
int n,k;
varf * radacina;
varf * arbore (int n)
{
varf * varfnou;
int ns, nd;
if (n==0) return NULL;
else
{
ns = n/2;
nd = n - ns - 1;
varfnou = new varf;
cin>>varfnou->cod;
varfnou->stang = arbore(ns);
varfnou->drept = arbore (nd);
return varfnou;
}
};
void tip (varf * nod,int &nivel)
{
do
{
cout<<" ";
nivel--;
} while (nivel > 0);
cout<<nod->cod;
};
void travers (enum trav modt, varf * rad, int nivel)
{
if (rad != NULL)
{
if (modt == preordine) tip (rad, nivel);
travers (modt, rad->stang, nivel+1);
if (modt == inordine) tip (rad, nivel);
travers (modt,rad->drept, nivel+1);
if (modt = postordine) tip (rad, nivel);
}
};
void traversare (enum trav modtrav)
{
travers(modtrav, radacina , 0);
};
main()
{
cout<<"\n\n\n Introduceti numarul de noduri: ";
cin>>n;
cout<<"\n Se dau elementele\n";
radacina=arbore(n);
Arad AA
Cluj CC
Timioara TT
Craiova CC
Bucureti BB
Constana CC
59 55
324 33
274 22
331 33
209 22
497 44
225 22
AAA
BBB
CCC
DDD
Graf neorientat GG
AAA
BBB
CCC
DDD
Graf orientat GG
AAA
BBB
CCC
DDD
222
444
333
333
AAA
BBB
CCC
DDD
Graf orientat puternic conectat GG
AAA
BBB
CCC
DDD
Graf orientat slab conectat GG
AAA
BBB
CCC
DDD
Nod liber NN
cout<<"\n Arborele total echilibrat :";
cout<<"\n in preordine :\n";
traversare(preordine);
cout<<"\n in inordine :\n";
traversare(inordine);
cout<<"\n in postordine :\n";
traversare(postordine);
}
Graful
1. Structura de date de tip graf
Proiectarea unui sistem informatic care s gestioneze reeaua naionala de ci ferate presupune crearea unui mediu de lucru capabil
s utilizeze baza de date a staiilor i pe cea a liniilor de cale ferate pentru a oferii soluii optime i reale care s minimizeze
costurile i timpul de folosire a reelei.
Lund de exemplu situaia real din figura urmtoarea:
Figura1. O parte a reelei de cale ferat
se pune problema parcurgerii traseului Arad Bucureti cu cost redus, acest lucru implicnd parcurgerea distanei cea mai scurt.
Sistemul prelucreaz informaiile iniiale, aflate n dou mulimi N i A, unde N = {Arad, Bucureti, Cluj, Craiova, Constana,
Timioara} este mulimea oraelor iar A = {Arad Timioara = 59 km, Timioara Craiova = 324 km, Craiova Bucureti = 209
km, Bucureti Constana = 225 km, Arad Cluj = 274 km, Cluj Craiova = 331 km, Cluj Bucureti = 497 km} este mulimea
distanelor dintre dou orae, i ofer soluia cutat.
Reprezentarea n memorie a acestor informaii care au multiple legturi ntre ele, astfel nct s permit parcurgerea complet a
zonelor sau localizarea unui element din structur, se face n situaia de fa utiliznd graful.
Graful, asemenea arborelui, este o structur n care relaia dintre nodul printe i nodul fiu este una ierarhic, dar care este mai
puin restrictiv n sensul c un nod are mai muli succesori dar i mai muli predecesori. El este definit ca o colecie de date
reunite n dou mulimi: mulimea N = { N1, N2, , Nn | n numrul de noduri al grafului }ce conine toate nodurile grafului i
mulimea A = { ( Ni, Nj ) = Aij | Ni, Nj

N i i,j = 1,n cu i

j }care conine arcele dintre dou noduri vecine.


Graful este larg utilizat n domeniile: ciberneticii, matematicii, cercetrilor operaionale n vederea optimizrii diferitelor activiti
economice, chimiei pentru descrierea structurii cristalelor, reelelor de transport de toate tipurile pentru optimizarea traseelor,
circuitelor electrice pentru simularea funcionri corecte, inteligenei artificiale i nu n ultimul rnd n domeniul analizei
aplicaiilor software.
Graful este de mai multe tipuri, fiind clasificat n funcie de :
- direcia arcelor; n cazul n care arcele dintre nodurile grafului sunt nedirecionate atunci graful este unul neorientat; cnd
exist sens ntre dou noduri Ni, Nj i arcul este direcionat (Ni

Nj sau Ni

Nj sau Ni

Nj) atunci graful este unul


orientat;
Figura 2. Graf orientat i neorientat
Arad AA
Cluj CC
Timioara TT
Craiova CC
Bucureti BB
Constana CC
59 55
324 33
274 22
331 33
209 22
497 44
225 22
AAA
BBB
CCC
DDD
Graf neorientat GG
AAA
BBB
CCC
DDD
Graf orientat GG
AAA
BBB
CCC
DDD
222
444
333
333
AAA
BBB
CCC
DDD
Graf orientat puternic conectat GG
AAA
BBB
CCC
DDD
Graf orientat slab conectat GG
0 7 5 0

0 0 8 1

0 0 0 3

0 0 0 0

0 1 1 0

0 0 1 1

0 0 0 1

0 0 0 0

AAA
BBB
CCC
DDD
Nod liber NN
- greutatea arcelor; dac oricare arc dintre dou noduri al grafului are asociat o valoare numeric ( care reprezint de cele mai
multe ori distana, durata de timp sau costul ) atunci graful este cu greutate; n cazul n care arcele nu au asociate valori
numerice, graful este unul fr greutate;
Figura 3. Graf orientat cu greutate
- existena arcelor; dac ntr-un graf nu exist nici un nod izolat, altfel spus pentru oricare nod Ni cu i = 1..n exist cel puin un
nod Nj cu
n j 1
i i

j pentru care exist arcul Aij asociat, atunci graful este conectat; un graf este neconectat dac
exist cel puin un nod izolat.
Figura 4. Graf orientat neconectat
La rndul lui graful orientat este puternic conectat dac ntre oricare dou noduri Ni i Nj cu i, j = 1..n exist drum ( un drum este
format din unul sau mai multe arce ) orientat de la i la j, Ni

Nj. Graful orientat este slab conectat dac ntre oricare dou noduri
Ni i Nj cu i, j = 1..n exist drum orientat de la i la j, Ni

Nj sau de la j la i, Ni

Nj ( doar unul dintre ele).


Figura 5. Tipuri de graf orientat
De exemplu n figura 5 se observ c al doilea graf orientat este slab conectat pentru c ntre nodul A i D exist drum orientat,
ns de la D la A nu exist drum.
2. Implementarea grafului
Exist numeroase metode de reprezentare n memoria calculatorului a grafului, fiecare cu avantajele i dezavantajele ei :
- matricea de adiacen;
- liste nlnuite;
- un vector de pointeri la liste simple sau dublu nlnuite de noduri adiacente;
- o list simplu sau dublu nlnuit de pointeri la liste simple sau dublu nlnuite de noduri adiacente;
- un vector de pointeri la liste simple sau dublu nlnuite de arce.
Dintre toate, cele mai utilizate metode sunt primele dou.
Matricea de adiacen
Reprezentarea prin matrice de adiacena a grafului este eficient cnd se cunoate numrul nodurilor i numrul mediu al arcelor;
acesta din urm trebuie s fie mare pentru ca gradul de umplere al matricei de adiacen s fie sczut. Cum crearea de software
optimizat nseamn i generalizarea problemei, lucru care d puine anse s se cunoasc numrul nodurilor i cel al arcelor,
singurul argument pro pentru aceast metod este dat doar de uurin implementrii i utilizrii matricelor. n cele mai multe
situaii reale, cea mai mare parte a memoriei necesar stocrii matricei de adiacen este nefolosit.
Pentru un graf cu n noduri este necesar o matrice ptratic M de dimensiuni [n][n], care pentru un n foarte mare ocup mult
spaiu.
Iniial matricea de adiacen are toate elementele egale cu valoarea 0. Pentru a reprezenta arcul Aij dintre nodurile Ni i Nj
(orientat de la Ni la Nj) la intersecia liniei i cu coloana j se trece valoarea 1, n cazul grafului cu fr greutate, sau greutatea
arcului, pentru graful cu greutate.
1, dac exist arc ntre nodul Ni i Nj;
Aadar M[i][j] =
AAA
BBB
CCC
DDD
222
444
333
333
AAA
BBB
CCC
DDD
Graf orientat puternic conectat GG
AAA
BBB
CCC
DDD
Graf orientat slab conectat GG
0 7 5 0

0 0 8 1

0 0 0 3

0 0 0 0

0 1 1 0

0 0 1 1

0 0 0 1

0 0 0 0

AAA
BBB
CCC
DDD
Nod liber NN
0, dac nu exist arc ntre nodul Ni i Nj;
, n cazul grafului fr greutate i :
aij, dac exist arc ntre nodul Ni i Nj, iar aij reprezint greutatea
Aadar M[i][j] = arcului
0, dac nu exist arc ntre nodul Ni i Nj;
n cazul unui graf neorientat, matricea de adiacen asociat este simetric.
Pentru graful cu 5 noduri :

7 1

8

5 3
A
B
C
D



A
B
C
D
Figura 6. Graf orientat cu greutate i fr greutate
Matricele de adiacen corespunztoare grafurilor sunt :
Figura 7. Matrice de adiacen
Lungimea drumului dintre dou noduri ale unui graf orientat fr greutate este dat de numrul de arce. Astfel n cazul grafului
din figura 6, ntre nodul A i D exist trei drumuri posibile, unul de lungime 3 (A-B-C-D) i dou de lungime 2 (A-C-D i A-B-
D).
Uurina lucrului cu matricea de adiacen const i n faptul c prin simple ridicri la putere se verific dac exist drum ntre
dou noduri i care este lungimea acestuia (doar n cazul grafului orientat fr greutate).
Fie M[4][4] matricea de adiacen din figura 7 asociat grafului orientat fr greutate, atunci obinem:
0 0 0 0
0 0 0 0
0 0 0 0
0 0 0 0

0 0 0 0
0 0 0 0
0 0 0 0
1 0 0 0

0 0 0 0
0 0 0 0
1 0 0 0
2 1 0 0
4 3 2
M M M
Dup cum se observ, dac M
k
[i][j] = val

0 atunci ntre nodurile Ni i Nj exist val drumuri pe direcia Ni

Nj, drumuri de
lungime k.
n cazul lui M
2
exist 2 drumuri de lungime 2 de la nodul A la nodul D (A-B-D i A-C-D), un drum de lungime 2 de la nodul A la
nodul C (A-B-C) i un drum de lungime 2 de la nodul B la nodul D (B-C-D).
Pentru k = 3 exist drumul de lungime 3 de la nodul a la nodul D (A-B-C-D).
Procesul de ridicare la putere se oprete cnd se ajunge la k = n, unde n este dimensiunea matricei.
Clasa graf care implementeaz diferite operaii cu grafuri reprezentate prin intermediul matricei de adiacen este:
#include <stdio.h>
#include <conio.h>
class graf_matrice
{
private:
int matm[20][20]; //matricea de muchii(adiacenta) 1=exista, 0=nu exista
long matc[20][20]; //matricea de costuri 100=nu e drum
int nr_noduri;
int nr_arce;
0 7 5 0

0 0 8 1

0 0 0 3

0 0 0 0

0 1 1 0

0 0 1 1

0 0 0 1

0 0 0 0

protected:
int vect_rez[20]; //vectorul n care se in minte drumuri
int nr_rez; //nr. nodurilor din rezultat
int matr[20][20]; //matricea rezultatelor obinute din prelucrri
int valid(int); //testez daca int se afla deja in vect soluie
int suma(int); //calculeaz lungimea drumului
public:
graf_matrice();
~graf_matrice();
void init(int tip_matrice); //iniializez graful folosind urmtoarele valori ptr.
//tip_matrice: 1=matm; 2=matc
void vect_r(); //afieaz vectorul rezultat
void matr_r(); //afieaz matricea rezultat
void matr_r1();
void drum_minim(); //se calculeaz drumul minim intre oricare 2 noduri
void este_drum(); //verifica existenta drumului intre oricare 2 noduri
void drum_minim(int, int); //drumul minim ntre 2 noduri date ca parametrii
void toate_drm(int,int); //toate drumurile dintre 2 noduri
void arbore(); //verific daca este sau nu arbore
void componente_conexe(); //determin componentele conexe
void eulerian(); //determin daca graful este sau nu eulerian
void parcurgere_bf(int); //parcurgerea grafului n lime
void parcurgere_df(int); //parcurgerea grafului n adncime
void hamiltonian(); //verific daca graful are cicluri hamiltoniene
void prim(); //determinare arbore parial de cost minim (alg Prim)
};
graf_matrice::graf_matrice()
{
nr_noduri=0;
nr_arce=0;
nr_rez=0;
for(int i=0; i<20; i++)
for(int j=0; j<20; j++)
{
matm[i][j]=0;
matc[i][j]=100; //asta e maximul in conventia mea
}
}
graf_matrice::~graf_matrice()
{
nr_noduri=0;
nr_arce=0;
nr_rez=0;
}
void graf_matrice::init(int tip_matrice)
{
if ((tip_matrice!=1)&&(tip_matrice!=2))
{
printf("Tip matrice invalid, folositi 1 sau 2 !!!");
return;
}
printf("\n\nIntroduceti nr. de noduri: ");
do
{
scanf("%d",&nr_noduri);
if (nr_noduri<=0) printf("Numar invalid de noduri !!!\n");
fflush(stdin);
}while(nr_noduri<=0);
if (tip_matrice==1)
{
printf("\nSe va introduce matricea de adiacenta\n");
printf("\nSe introduc valorile 1-daca este drum; 0-daca nu este drum\n");
}
else printf("\nSe va introduce matricea de costuri\n");
for (int j=0; j<nr_noduri; j++)
for (int i=0; i<j; i++)
{
printf("m[%d][%d] = ", i+1, j+1);
if (tip_matrice==1)
{
do
{
scanf("%d", &matm[i][j]);
matm[j][i]=matm[i][j];
}
while ((matm[i][j]!=0)&&(matm[i][j]!=1));
if (matm[i][j])
{
nr_arce++;
matc[i][j]=1;
matc[j][i]=1;
}
else
{
matc[i][j]=100;
matc[j][i]=100;
}
}
else
{
do
{
scanf("%d", &matc[i][j]);
matc[j][i]=matc[i][j];
}
while (matc[i][j]<0);
if (matc[i][j]!=0)
{
nr_arce++;
matm[i][j]=1;
matm[j][i]=1;
}
if (matc[i][j]==0)
{
matc[i][j]=100;
//daca la introducerea valorilor arcelor
matc[j][i]=100;
matm[i][j]=0;
//un arc are valoarea 0, el nu exista
matm[j][i]=0;
}
}
}
}
void graf_matrice::vect_r()
{
printf("Vectorul rezultat este :\n");
for (int i=0; i<nr_rez; i++)
printf("%d ", vect_rez[i]);
printf("\n");
}
void graf_matrice::matr_r()
{
for (int i=0; i<nr_noduri; i++)
for (int j=0; j<i; j++)
if (matr[i][j]) printf("\nintre %d si %d exista drum ",i+1,j+1);
else printf("\nintre %d si %d nu exista drum ",i+1,j+1);
}
void graf_matrice::matr_r1()
{
for (int i=0; i<nr_noduri; i++)
for (int j=0; j<i; j++)
if (matr[i][j]!=100) printf("\nintre %d si %d cost minim %d",i+1,j+1,matr[i][j]);
else printf("\nintre %d si %d nu exista drum ",i+1,j+1);
}
void graf_matrice::drum_minim()
{
for (int i=0; i<nr_noduri; i++)
for (int j=0; j<nr_noduri; j++)
matr[i][j]=matc[i][j];
for (int k=0; k<nr_noduri; k++)
for (int i=0; i<nr_noduri; i++)
for (int j=0; j<nr_noduri; j++)
matr[i][j]=(matr[i][j]<matr[i][k]+matr[k][j]) ? matr[i][j] : matr[i][k]+matr[k][j];
}
void graf_matrice::este_drum()
{
for (int i=0; i<nr_noduri; i++)
for (int j=0; j<nr_noduri; j++)
matr[i][j]=matm[i][j];
for (int k=0; k<nr_noduri; k++)
for (int i=0; i<nr_noduri; i++)
for (int j=0; j<nr_noduri; j++)
matr[i][j]=matr[i][j]||(matr[i][k]&&matr[k][j]);
}
int graf_matrice::valid(int k)
{
if (matc[vect_rez[k-1]][vect_rez[k]]==100) return 0;
for (int i=0; i<k; i++)
if (vect_rez[i]==vect_rez[k]) return 0;
return 1;
}
int graf_matrice::suma(int k)
{
int lg=0;
for (int i=0; i<k; i++)
lg+=matc[vect_rez[i]][vect_rez[i+1]];
return lg;
}
void graf_matrice::drum_minim(int a, int b)
{
int h, vect[20], lgdrum, min = 100;
for (int f=0; f<20; f++)
vect_rez[f]=-1;
vect_rez[0]=a;
h=1;
while(h>=1)
{
while(vect_rez[h]<nr_noduri)
{
vect_rez[h]++;
if(valid(h))
if(vect_rez[h]==b)
{
lgdrum=suma(h);
if(lgdrum<min)
{
for (int e=0;e<=h;e++)
vect[e]=vect_rez[e];
min=lgdrum;
nr_rez=h+1;
}
}
else
{
h++;
vect_rez[h]=-1;
}
}
h--;
}
for (int e=0; e<nr_rez; e++)
vect_rez[e]=vect[e];
}
void graf_matrice::arbore()
{ int b[20],i,j,v,s;
v=0;
for (i=0;i<nr_noduri;i++)
for(j=i+1;j<nr_noduri;j++)
if(matm[i][j]==1) v++;
for(i=0;i<nr_noduri;i++) b[i]=0;
b[0]=1;
for(i=0;i<nr_noduri;i++)
for(j=0;j<nr_noduri;j++)
if((matm[i][j]==1)&&(b[i]==1)) b[j]=1;
s=0;
for (i=0;i<nr_noduri;i++)
if(b[i]==0) s++;
if((s==0)&&(v==nr_noduri-1)) printf("\n Graful este arbore");
else printf("\n Graful nu este arbore");
getch();
}
void graf_matrice::eulerian()
{
int b[20],i,j,k,v,s;
for(i=0;i<nr_noduri;i++) b[i]=0;
b[0]=1;
for(i=0;i<nr_noduri;i++)
for(j=0;j<nr_noduri;j++)
if((matm[i][j]==1)&&(b[i]==1)) b[j]=1;
s=0;
for (i=0;i<nr_noduri;i++) if(b[i]==0) s++;
for(i=0;i<nr_noduri;i++)
{
k=0;
for(j=0;j<nr_noduri;j++) if(matm[i][j]==1) k=k+1;
v=k/2;
if ((k-2*v)>0)s=1;
}
if(s>0) printf("\n Graful nu este eulerian");
else printf("\n Graful este eulerian");
getch();
}
void graf_matrice::parcurgere_bf(int i)
{
int j,u,p,v,c[20],viz[20];
for(j=0;j<nr_noduri;j++) viz[j]=0;
c[1]=i;p=1;u=1;viz[i]=1;
while(p<=u)
{
v=c[p];
for(j=0;j<nr_noduri;j++)
if ((matm[v][j]==1)&&(viz[j]==0))
{
u++;
c[u]=j;
viz[j]=1;
}
p++;
}
printf("lista varfurilor parcurse cu metoda BF pornind de la varful %d ",i+1);
for(j=2;j<=u;j++) printf("%d ",c[j]+1);
}
void graf_matrice::parcurgere_df(int i)
{
int viz[20],urm[20],s[20],k,v,j,ps;
for(j=0;j<nr_noduri;j++)
{
viz[j]=0;
urm[j]=0;
}
s[1]=i;ps=1;
viz[i]=1;
printf("ordinea in DF este %d",i+1);
while(ps>=1)
{
j=s[ps];
k=urm[j]+1;
while ( (k<=nr_noduri) && ( (matm[j][k]==0) || (matm[j][k]==1) && (viz[k]==1) ) )
k++;
urm[j]=k;
if(k==nr_noduri+1) ps--;
else
{
printf("%d",k+1);
viz[k]=1;
ps++;
s[ps]=k;
}
}
}
void graf_matrice::prim()
{
int s[20],t[20],p[20];
int min,k,l,c,i,j,v;
printf("\n nodul de pornire");
scanf("%d",&v);
for(i=0;i<nr_noduri;i++)
{
s[i]=0;
t[i]=0;
p[i]=0;
}
s[v-1]=1;
for(k=1;k<=nr_noduri-1;k++)
{
min=100;
for(i=0;i<nr_noduri;i++)
for(j=0;j<nr_noduri;j++)
if ((s[i]==1)&&(s[j]==0)&&(min>matc[i][j]))
{
min=matc[i][j];
l=i;
c=j;
}
s[c]=1;
t[c]=l+1;
p[c]=matc[l][c];
}
for(i=0;i<nr_noduri;i++)
printf("%d ",t[i]);
printf("\n");
for(i=0;i<nr_noduri;i++)
printf("%d ",p[i]);
}
void graf_matrice::hamiltonian()
{
int x[20],v,k,j,sol,i;
sol=0;
x[1]=1;k=2;
x[2]=1;
while(k>1)
{
v=0;
while((x[k]+1<=nr_noduri)&&(v==0))
{
x[k]++;
v=1;
for(i=1;i<=k-1;i++)
if(x[k]==x[i])
{
v=0;
break;
}
if(matm[x[k-1]-1][x[k]-1]==0) v=0;
}
if(v==0) k--;
else if ((k==nr_noduri)&&(matm[x[nr_noduri]-1][x[1]-1]==1))
{
sol++;
if(sol==1) printf("\ncicluri hamiltoniene\n");
for(j=1;j<=nr_noduri;j++) printf("%d ",x[j]);
printf("\n");
}
else if(k<nr_noduri)
{
k++;
x[k]=1;
}
}
if (sol==0) printf("Graful nu este hamiltonian");
}
void graf_matrice::componente_conexe()
{
int b[20],k,j,i;
for(i=0;i<nr_noduri;i++)
for(j=0;j<nr_noduri;j++)
matr[i][j]=matm[i][j];
printf("\n Componentele conexe sunt : ");
for(k=0;k<nr_noduri;k++)
{
for(j=0;j<nr_noduri;j++) b[j]=-2;
b[k]=k;
if(matr[k][k]>-1)printf("\n ");
for(i=0;i<nr_noduri;i++)
for(j=0;j<nr_noduri;j++)if((matr[i][j]==1)&&(b[i]==k))
{
b[j]=k;
matr[i][j]=0;
matr[j][i]=0;
}
for(j=0;j<nr_noduri;j++) if((b[j]==k)&&(matr[j][j]>-1))
{
matr[j][j]=-1;
printf(" %d",j+1);
}
}
}
void graf_matrice::toate_drm(int a, int b)
{
int h;
for (int f=0; f<20; f++)
vect_rez[f]=-1;
vect_rez[0]=a;
h=1;
while(h>=1)
{
while(vect_rez[h]<nr_noduri)
{
vect_rez[h]++;
if(valid(h))
if(vect_rez[h]==b)
{
printf("\n");
for (int e=0;e<=h;e++)
printf("%d ", vect_rez[e]+1);
}
else
{
h++;
vect_rez[h]=-1;
}
}
h--;
}
printf("\n");
}
Liste nlnuite
De cele mai multe ori nu se cunoate numrul de noduri ale grafului, apelndu-se la construirea dinamic a grafului pe parcursul
rezolvrii problemei, deci nu se cunoate dimensiunea matricei de adiacen. n aceste situaii graful este reprezentat printr-o reea
de liste nlnuite. Asemenea matricei de adiacen descrierea grafului cuprinde mulimea de noduri i pe cea de arce, preciznd
orientarea arcului i dup caz greutatea lui.
Se definete structura arcs care este asociat elementelor din mulimea arcelor:
struct arc {
struct nodgraf * destinaie; /*adresa nodului ctre care
exist arc;*/
struct arc* next_arc; /*referin ctre elementul urmtor
din lista de arce;*/
int greutate; //greutatea arcului;
}
Este vorba de o list a arcelor ce este construit dinamic. Structura este cea a unei liste oarecare, cuprinznd informaia propriu-
zis, greutatea arcului, precum i cea necesar nlnuirii n list, adresa elementului urmtor. Cu toate c nodgraf * destinaie este
un pointer, el face parte din informaia de baz i nu din cea destinat regsirii n list. n list exist mai multe liste, organizate pe
principiul descendenei dintr-un nod. Cum fiecare nod din graf este unic, se elimin astfel posibilitatea ca un arc s fie n mai
multe liste.
Tipul de structura nodgraf este tot o structur de tip list. Pe lng informaia nodului i adresa urmtorului nod, ea conine i
adresa de start a listei ce cuprinde arcele descendente din nodul respectiv.
struct nodgraf {
int info; //informaia nodului;
struct nodgraf* next; //referin ctre urmtorul nod;
struct arc *capat; //captul listei de arce;
}
La crearea grafului se introduc iniial informaiile nodurilor, crendu-se astfel lista lor. Dup aceasta se vor crea listele de arce
introducndu-se informaia nodului surs, a nodului destinaie i greutatea arcului.
Pentru graful cu greutate din figura 6 reprezentarea sa n memorie prin intermediul listelor de liste este:

&C
&C &B
A
&D
&D
7
5
8
1
3
NULL
NULL
NULL
NULL
D C B
NULL
&nod reprezint adresa lui nod
Figura 8. Reprezentarea n memorie a unui graf cu ajutorul listelor
Clasa graf care implementeaz graful definit cu ajutorul listelor nlnuite este:
#include <iostream.h>
#include <conio.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define nmax 50
#define MAXINT 32565
typedef struct arc
{
struct nodgraf *destinatie;
//adresa nodului catre care exista arc;
int greutate; //greutatea arcului;
struct arc *next_arc;
//referinta catre elementul urmator din lista de arce;
}arc;
typedef struct nodgraf
{
int info; //informatia nodului;
struct nodgraf *next; //referinta catre urmatorul nod;
struct arc *capat; //capatul listei de arce;
}nodgraf;
typedef struct stiva
{
nodgraf *n; //elementul stivei
struct stiva *next; //referinta catre urmatorul element;
}stiva;
struct lista
{
nodgraf *n; //elementul listei
struct lista *next; //referinta catre urmatorul element;
};
typedef struct coada
{
struct lista *pred;
struct lista *succ;
}coada;
/********************************************************************/
/********************************************************************/
class graf_liste
{ int nr;
public:
graf_liste(){}
graf_liste(int nrnoduri){ nr=nrnoduri;}
nodgraf *inserare_nod(nodgraf *,int); //insereaza un nod in graf
nodgraf *gaseste_nod(nodgraf *, int); //gaseste un nod in graf
void inserare_arc(nodgraf *,int,int,int); //insereaza arc intre 2 noduri
int adiacent(nodgraf *,nodgraf *); //verifica daca 2 noduri sunt adiacente
int sterge_arc(nodgraf *,nodgraf *); //sterge arcul dintre 2 noduri
void vizitare(nodgraf *nd,int vizitat[]) //marcheaza nodul ca vizitat
{
vizitat[nd->info]=1;
cout<<nd->info<<" - ";
}
stiva *push(stiva *stk,nodgraf *nd) //pune un element in stiva
{ stiva *t=(stiva*)malloc(sizeof(struct stiva));
t->n=nd;
t->next=stk;
return t;
}
stiva *pop(stiva *stk,nodgraf **nd) //scoate un element din stiva
{ stiva *t;
if(!stk) return NULL;
t=stk->next;
*nd=stk->n;
free(stk);
return t;
}
void depth(nodgraf *); //parcurgere in adancime
void put(struct coada *q, nodgraf *nd)
{ struct lista *t,*keep=q->succ;
t=(struct lista *)malloc(sizeof(struct lista));
t->n=nd;
t->next=NULL;
if(keep)keep->next=t;
else q->pred=t;
q->succ=t;
}
nodgraf *get(struct coada *q) //scoate un element din coada
{ struct lista *t;
nodgraf *n;
if(q->pred==NULL) return NULL;
else { t=q->pred;
n=t->n;
if(q->pred==q->succ)q->succ=NULL;
q->pred=q->pred->next;
}
free(t);
return n;
}
void breadth(nodgraf *); //parcurgere in latime
int drum_minim(nodgraf *,int,int,int[]); //gaseste drumul minim
void stergere_nod(nodgraf *&,int);// sterge un nod din graf
};
//********************************************************************
//********************************************************************
nodgraf* graf_liste::inserare_nod(nodgraf *cap,int info)
{ nodgraf *nou,*temp;
nou=(nodgraf *)malloc(sizeof(nodgraf));
nou->info=info;
nou->next=NULL;
nou->capat=NULL;
if(cap==NULL)return nou;
else
{ temp=cap;
while(temp->next!=NULL) temp=temp->next;
temp->next=nou;
return nou;
}
}
//*********************************************************************
nodgraf* graf_liste::gaseste_nod(nodgraf *cap, int info)
{ nodgraf *p;
int gasit;
p=cap;
gasit=0;
while((p!=NULL)&&(gasit==0))
if(p->info==info)gasit=1;
else p=p->next;
return p;
}
//**********************************************************************
void graf_liste::inserare_arc(nodgraf *cap,int sursa,int dest,int greutate)
{ nodgraf *s,*d;
arc *temp,*keep=NULL;
int gasit;
s=gaseste_nod(cap,sursa);
if(s==NULL) s=inserare_nod(cap,sursa);
d=gaseste_nod(cap,dest);
if(d==NULL) d=inserare_nod(cap,dest);
temp=s->capat;
gasit=0;
while(temp&&(!gasit))
if(temp->destinatie==d)
{ temp->greutate=greutate;
gasit=1;
}
else { keep=temp;
temp=temp->next_arc;
}
if(!gasit)
{ temp=(arc*)malloc(sizeof(arc));
temp->destinatie=d;
temp->greutate=greutate;
temp->next_arc=NULL;
if(!keep) s->capat=temp;
else keep->next_arc=temp;
}
}
//**************************************************************
int graf_liste::adiacent(nodgraf *s,nodgraf *d)
{ arc *temp;
int gasit=0;
temp=s->capat;
while(temp&&(!gasit))
if(temp->destinatie==d) gasit=1;
else temp=temp->next_arc;
if(gasit) return temp->greutate;
else return 0;
}
//***************************************************************
int graf_liste::sterge_arc(nodgraf *s,nodgraf *d)
{ arc *temp,*keep=NULL;
int deleted=0;
temp=s->capat;
while(temp&&(!deleted))
if(temp->destinatie==d)
{ if(!keep) s->capat=temp->next_arc;
else keep->next_arc=temp->next_arc;
free(temp);
deleted=1;
}
else { keep=temp;temp=temp->next_arc;}
return deleted;
}
//****************************************************************
void graf_liste::depth(nodgraf *g)
{ int vizitat[nmax],i;
nodgraf *curent,**nd;
arc *temp;
stiva *stk=NULL;
for(i=0;i<nmax;i++) vizitat[i]=0;
while(g)
{ if(!vizitat[g->info])
{ cout<<endl<<"Componenta : "<<endl;
stk=push(stk,g);
do
{ stk=pop(stk,nd);
curent=*nd;
vizitare(curent,vizitat);
temp=curent->capat;
while(temp)
{ if(!vizitat[temp->destinatie->info])
stk=push(stk,temp->destinatie);
temp=temp->next_arc;
}
} while(stk);
}
g=g->next;
}
}
//************************************************************
void graf_liste::breadth(nodgraf *g)
{ int vizitat[nmax],i;
nodgraf *curent;
arc *temp;
coada *q,coada={NULL,NULL};
q=&coada;
for(i=0;i<nmax;i++) vizitat[i]=0;
while(g)
{ if(!vizitat[g->info])
{ cout<<endl<<"Componenta : "<<endl;
put(q,g);
do
{ curent=get(q);
if(!vizitat[curent->info])
{ vizitare(curent,vizitat);
temp=curent->capat;
while(temp)
{ if(!vizitat[temp->destinatie->info])
put(q,temp->destinatie);
temp=temp->next_arc;
}
}
} while(q->pred);
}
g=g->next;
}
}
AAA
BBB
CCC
DDD
EEE
FFF
AAA
BBB
CCC
Lista nodurilor vizitate LL
Stiva nodurilor de vizitat SS
DDD
Noduri
adiacente aa
AAA
BBB
DDD
Lista nodurilor vizitate LL
Stiva nodurilor de vizitat SS
CCC
EEE
FFF
Noduri
adiacente aa
//******************************************************************
int graf_liste::drum_minim(nodgraf *g,int sursa,int dest,int precede[nmax])
{ nodgraf *tmp;
arc *temp;
int distanta[nmax],i,k,min,curent,perm[nmax],dc,distanta_noua;
for(i=0;i<nmax;i++)
{ distanta[i]=precede[i]=MAXINT;
perm[i]=-1;
}
distanta[sursa]=0;
curent=sursa;
perm[sursa]=1;
while(curent!=dest)
{ dc=distanta[curent];
tmp=gaseste_nod(g,curent);
temp=tmp->capat;
while(temp)
{ distanta_noua=dc+temp->greutate;
tmp=temp->destinatie;
if(distanta_noua<distanta[tmp->info])
{ distanta[tmp->info]=distanta_noua;
precede[tmp->info]=curent;
}
temp=temp->next_arc;
}
for(i=0;(i<nmax)&&(perm[i]>0);i++);
k=i;
min=distanta[k];
for(i=k;i<nmax;i++)
if((perm[i]<0)&&(distanta[i]<min))
{ min=distanta[i];
k=i;
}
curent=k;
perm[k]=1;
}
return distanta[dest];
}
//********************************************************************
void graf_liste::stergere_nod(nodgraf *&temp,int sursa)
{
if(temp->info==sursa)
{
nodgraf *a=temp;
temp=a->next;
free(a);
}
else stergere_nod(temp->next,sursa);
}
//SFARSIT
3. Traversarea unui graf
Un graf este n esen o reea, care de cele mai multe ori are coresponden n lume real. Cum principala caracteristic a unei
reele este mobilitatea continu din interiorul su, se pune problema parcurgerii grafului. n cazul altor structuri de date, vectori,
liste i chiar arbori lucrurile sunt clare: se pornea de la un capt i trecndu-se de la un element la urmtorul se parcurgea integral
structura fr ca un element s fie vizitat de mai multe ori.
Graful fiind o structur de date mai general n care nodurile au mai mult de un predecesor se pune deci problema trecerii o
singur dat prin fiecare nod. Pentru a complica mai mult problema se ia n considerare i faptul c oricare nod al grafului este un
posibil punct de start al traversrii, lucru care demonstreaz c aceasta nu este unic, rezultatele variind de la caza la caz.
Evitarea revenirii ntr-un nod vizitat se face asociind acestuia o etichet care s indice acest lucru. Metodele de traversare a
grafului sunt bazate pe acest principiu, deosebindu-le doar modul n care stocheaz i revin asupra unor direcii necercetate.
Cele dou metode sunt :
- traversarea n adncime (depth-first traversal);
- traversarea n lime (breadth-first traversal).
AAA
BBB
CCC
DDD
EEE
FFF
AAA
BBB
CCC
Lista nodurilor vizitate LL
Stiva nodurilor de vizitat SS
DDD
Noduri
adiacente aa
AAA
BBB
DDD
Lista nodurilor vizitate LL
Stiva nodurilor de vizitat SS
CCC
EEE
FFF
Noduri
adiacente aa
AAA
EEE
FFF
Lista nodurilor vizitate LL
Stiva nodurilor de vizitat SS
CCC DDD
Nu are noduri
adiacente aa
BBB
AAA EEE FFF
Lista nodurilor vizitate LL
Stiva nodurilor de vizitat SS
CCC DDD
Noduri adiacente NN
BBB CCC
FFF
AAA EEE FFF
Lista nodurilor vizitate LL
CCC DDD BBB
AAA BBB CCC
CCC
Noduri
adiacente aa
FFF
AAA
CCC
DDD
FFF
EEE
BBB
Nivel 1 NN
Nivel 2 NN
Nivel 3 NN
Nivel 4 NN
Nivel 5 NN
Nivel 6 NN
Figura 10. Arbore acoperitor n adncime pentru graful din figura 9 FF
Pe scurt, cele dou traversri sunt asemenea drumului parcurs de exploratori ntr-o peter, numai c n cazul traversrii n
adncime avem un singur explorator care se ntoarce de fiecare dat cnd ajunge la un capt de drum la ultima intersecie, iar n
cazul traversrii n lime sunt o echip, fiecare lund-o pe un drum.
Odat traversat graful cu una dintre aceste metode, se creeaz o pdure acoperitoare pentru el, lucru util pentru punerea n
eviden a componentelor sale conexe, dar i un arbore acoperitor. Arborele acoperitor este un subgraf ce conine nodurile grafului
iniial i doar attea arce nct s fie construit un arbore.
Pentru un graf implementat prin intermediul unei matrice de adiacen, ordinul de complexitate al operaiei de traversare este O
(n
2
). Graful cu n noduri, are matricea asociat de dimensiune [n][n]. Rezult c timpul alocat prelucrrii unui nod n vederea
gsirii tuturor nodurilor adiacente este O (n); se parcurge linia de n elemente a nodului. Deci pentru n noduri timpul necesar
traversrii este de n*O (n) = O (n
2
). Dup cum se observ, indicatorul depinde doar de numrul nodurilor, numrul arcelor dintre
noduri neavnd nici o influen.
n cealalt situaie, pentru un graf reprezentat cu ajutorul listelor nlnuite, ordinul de complexitate al operaiei de traversare este
cuprins ntre O (n) i O (n
2
). Indicatorul depinde aici de numrul de arce al fiecrui nod. Cel mai fericit caz este acela cnd nu
exist nici un arc ntre noduri i atunci traversarea are ordinul de complexitate minim O(n). Dac fiecare nod al grafului are arce
ctre toate celelalte n-1 noduri ale grafului, se obine complexitatea maxim O (n
2
).
Traversarea n adncime (DFS)
Procesul de traversare n adncime a unui graf, este unul de tip backtracking, analogic cu traversarea n preordine a unui arbore.
Algoritmul folosete n acest scop un vector sau o list n care pune nodurile vizitate i o stiv n care sunt puse nodurile adiacente
nodului curent. Odat vizitat un nod, traversarea se ndeprteaz n adncime pn cnd ajunge la un capt de drum.
Fie nodul de start al parcurgerii, nodul notat cu X. Acesta este etichetat ca vizitat i este trecut n list. Toate n nodurile adiacente
lui X, Xi cu i = 1..n, sunt puse n stiva de ateptare. Primul nod din stiv, X1, este verificat dac nu este n list, caz n care este
vizitat, fiind scos i pus n list. n cealalt situaie, nodul se afla deja n list, el este scos din stiv i este verificat nodul de sub el.
Aceti pai sunt repetai pentru fiecare nod adiacent al lui X1.
Altfel spus, se pleac pe drumul dat de primul nod adiacent al nodului de start, primul nod adiacent al nodului deja vizitat i tot
aa pn cnd se ajunge la un nod al crui prim nod adiacent a fost vizitat sau nu exist fiind un capt de drum. Atunci se trece la
urmtorul nod adiacent pe care se continu, dac este posibil, sau n acest moment, algoritmul se ntoarce la penultimul nod vizitat
i pleac pe al doilea nod adiacent al acestuia, n condiiile n care el nu a fost vizitat i exist. Algoritmul se ntoarce atta timp
ct exist noduri n stiv.
Parcurgerea n adncime a grafului :
Figura 9. Graf orientat
presupune parcurgerea etapelor :
- se alege nodul A ca punct de start al traversrii. Nodul A este vizitat i este trecut n lista nodurilor pe la care s-a trecut. n
stiv sunt trecute nodurile ctre care are arce direcionate : B i C;
- se scoate primul nod din stiv, C, i cum acesta nu a fost vizitat (nu se afla n lista nodurilor vizitate) este trecut acum n list.
Nodurile sale adiacente, doar D, sunt trecute n stiv;
- se scoate nodul D din stiv i este pus n list, deoarece nu a fost vizitat. Nodurile sale adiacente, F i E, se pun n stiv;
AAA
BBB
CCC
DDD
EEE
FFF
AAA
BBB
CCC
Lista nodurilor vizitate LL
Stiva nodurilor de vizitat SS
DDD
Noduri
adiacente aa
AAA
BBB
DDD
Lista nodurilor vizitate LL
Stiva nodurilor de vizitat SS
CCC
EEE
FFF
Noduri
adiacente aa
AAA
EEE
FFF
Lista nodurilor vizitate LL
Stiva nodurilor de vizitat SS
CCC DDD
Nu are noduri
adiacente aa
BBB
AAA EEE FFF
Lista nodurilor vizitate LL
Stiva nodurilor de vizitat SS
CCC DDD
Noduri adiacente NN
BBB CCC
FFF
AAA EEE FFF
Lista nodurilor vizitate LL
CCC DDD BBB
AAA BBB CCC
Lista nodurilor vizitate LL Coada nodurilor de vizitat CC
CCC
Noduri
adiacente aa
FFF
DDD
AAA CCC DDD
Lista nodurilor vizitate LL Coada nodurilor de vizitat CC
FFF
Noduri
adiacente aa
EEE
BBB CCC FFF
AAA FFF
Lista nodurilor vizitate LL Coada nodurilor de vizitat CC
Noduri
adiacente aa
CCC
BBB CCC EEE FFF DDD
AAA
Lista nodurilor vizitate LL
BBB CCC EEE FFF DDD
AAA
CCC
DDD FFF
EEE
BBB
Nivel 1 NN
Nivel 2 NN
Nivel 3 NN
Nivel 4 NN
AAA
CCC
DDD
FFF
EEE
BBB
Nivel 1 NN
Nivel 2 NN
Nivel 3 NN
Nivel 4 NN
Nivel 5 NN
Nivel 6 NN
Figura 10. Arbore acoperitor n adncime pentru graful din figura 9 FF
AAA
BBB
DDD
FFF
- se scoate nodul din stiv nodul F i este etichetat ca vizitat. n acest punct se ajunge la un sfrit de drum i astfel trece la
urmtorul element din stiv;
- se viziteaz nodul E. Iniial se trece n stiv nodul adiacent lui E, anume nodul F, dar el este scos apoi din stiv existnd,
deja n lista nodurilor vizitate. n stiv rmne doar nodul B;
- traversarea este completat prin vizitarea nodului B. Cele dou noduri adiacente ale sale, F i C, sunt trecute n stiv, ns
sunt scoase apoi unul cte unul, ele fiind deja nsemnate ca vizitate.
La scrierea codului surs, algoritmul se mbuntete fcndu-se o cutare n list a nodurilor care se introduc n stiv pentru a se
vedea dac sunt sau nu deja vizitate. Traversarea grafului neorientat nu implic modificarea n vreun fel a algoritmului, acesta
fiind aplicat fr nici o restricie.
Arborele acoperitor este construit odat cu lista nodurilor vizitate, adugnd un nod la list se completeaz i arborele.
Traversarea grafului, folosind acest procedeu, d un rezultat diferit pentru un nod de start altul dect A, acest lucru fiind valabil i
pentru arborele acoperitor din figura 10.
Traversarea n lime (BFS)
Procesul de traversare n lime a unui graf orientat sau neorientat, este analog procesului de traversare n inordine a unui arbore,
i const n parcurgerea o singur dat a tuturor nodurilor din graf.
Deosebirile de cealalt metod constau n folosirea unei cozi de data aceasta pentru a pstra nodurile de verificat, i n faptul c
algoritmul se ndeprteaz de nodul vizitat doar dup ce a examinat i vizitat , dac este posibil, toi succesorii si. n schimb i
aceast metod este aplicabil att grafului orientat ct i neorienatat dnd rezultate ce variaz n funcie de alegerea nodului de
pornire.
Parcurgerea n lime a grafului din figura 9, presupune paii:
- se alege nodul A ca punct de start al traversrii. Nodul A este vizitat i este trecut n lista nodurilor pe la care s-a trecut. n
coad sunt trecute nodurile ctre care are arce (direcionate sau nedirecionate, n funcie de tipul grafului) : B i C;
AAA
EEE
FFF
Lista nodurilor vizitate LL
Stiva nodurilor de vizitat SS
CCC DDD
Nu are noduri
adiacente aa
BBB
AAA EEE FFF
Lista nodurilor vizitate LL
Stiva nodurilor de vizitat SS
CCC DDD
Noduri adiacente NN
BBB CCC
FFF
AAA EEE FFF
Lista nodurilor vizitate LL
CCC DDD BBB
AAA BBB CCC
Lista nodurilor vizitate LL Coada nodurilor de vizitat CC
CCC
Noduri
adiacente aa
FFF
DDD
AAA CCC DDD
Lista nodurilor vizitate LL Coada nodurilor de vizitat CC
FFF
Noduri
adiacente aa
EEE
BBB CCC FFF
AAA FFF
Lista nodurilor vizitate LL Coada nodurilor de vizitat CC
Noduri
adiacente aa
CCC
BBB CCC EEE FFF DDD
AAA
Lista nodurilor vizitate LL
BBB CCC EEE FFF DDD
AAA
CCC
DDD FFF
EEE
BBB
Nivel 1 NN
Nivel 2 NN
Nivel 3 NN
Nivel 4 NN
AAA
CCC
DDD
FFF
EEE
BBB
Nivel 1 NN
Nivel 2 NN
Nivel 3 NN
Nivel 4 NN
Nivel 5 NN
Nivel 6 NN
Figura 10. Arbore acoperitor n adncime pentru graful din figura 9 FF
AAA
BBB
CCC
DDD
EEE
FFF
AAA
BBB
CCC
DDD
EEE
FFF
- sunt verificate nodurile adiacente i sunt vizitate dac nu se afl deja n list. n momentul trecerii n lista nodurilor deja
parcurse, nodurile lor adiacente sunt adugate la coad, nodul F i C adiacente lui B i nodul D adiacent lui C;
- din coad trec n lista nodurilor traversate, nodurile F i D. Nodul C exist deja n list i doar este scos din coad. Nodul F
nu are adiaceni i reprezint un capt de drum, nici un nod nefiind adugat n coad. n schimb, coada este completat cu
nodurile E i F, care sunt adiacente lui D;
- traversarea este ncheiat prin adugarea nodului E la list. Nodurile F i C au fost vizitate i nu se mai pun iar n list.
Ca i n cazul metodei precedente, algoritmul se optimizeaz verificndu-se nainte de a fi pus n coada de ateptare dac nodul
respectiv se afl n list sau nu.
Figura 11. Arbore acoperitor n lime pentru graful din figura 9
Arborele acoperitor este construit odat cu lista nodurilor vizitate. Adugnd un nod la list se completeaz i arborele, iar toate
nodurile adiacente cu acesta i care nu au fost vizitate sunt adugate la arbore ca noduri copii (ulterior devin noduri printe pentru
nodurile adiacente din graf).
n concordan cu rezultatul dat de traversarea n lime a arborelui, i forma arborelui acoperitor variaz n funcie de nodul de
start.
4. nchiderea tranzitiv a grafului
Graful este de cele mai multe ori reprezentarea matematic a problemelor economice i nu numai, legate de transport, de costul
deplasrii dintr-un punct n altul, de durata realizrii acestuia. Cea mai sugestiv aplicaie legat de implicarea grafului n
rezolvarea acestor probleme este cea a drumului minim, ns de multe ori este necesar s se tie doar dac este drum ntre dou
noduri. Soluia acestei probleme este dat de realizarea unei matrice, numit nchiderea tranzitiv a matricei de adiacen, care s
arate pentru fiecare nod n parte unde se poate ajunge plecnd din el.
O modalitate de creare a acesteia este dat de traversarea n adncime a grafului. Traversnd graful din fiecare nod al su, se obin
attea liste cte noduri sunt, liste care arat n ce noduri se ajunge din nodul de start. Acestea din urm se transpun ntr-o matrice
M[n][n], care are elementul mij =1 dac exist drum de la nodul Ni la nodul Nj i 0 n rest.
Pentru graful :
traversarea prin metoda DFS pornind din fiecare nod are ca rezultat urmtoarele liste :
AAA CCC DDD
Lista nodurilor vizitate LL Coada nodurilor de vizitat CC
FFF
Noduri
adiacente aa
EEE
BBB CCC FFF
AAA FFF
Lista nodurilor vizitate LL Coada nodurilor de vizitat CC
Noduri
adiacente aa
CCC
BBB CCC EEE FFF DDD
AAA
Lista nodurilor vizitate LL
BBB CCC EEE FFF DDD
AAA
CCC
DDD FFF
EEE
BBB
Nivel 1 NN
Nivel 2 NN
Nivel 3 NN
Nivel 4 NN
AAA
BBB
CCC
DDD
EEE
FFF
AAA
BBB
CCC
DDD
EEE
FFF
AAA
BBB DDD
FFF
777
333
444
888
111
20 22
- pornind din A am : A, C, D, F, E, B;
- pornind din B am : B, C, D, F, E;
- pornind din C am : C, D, F, E;
- pornind din D am : D, F, E, C;
- pornind din E am : E, F, C, D;
- pornind din F am : F.
Matricea nchiderii tranzitive obinute prin intermediul listelor este :
1 0 0 0 0 0
1 1 1 1 0 0
1 1 1 1 0 0
1 1 1 1 0 0
1 1 1 1 1 0
1 1 1 1 1 1
.
Folosind matricea, crem graful extins numit nchidere tranzitiv. Lum fiecare nod n parte, iar pe reprezentarea grafului iniial
se deseneaz sgei punctate ctre nodurile la care se ajunge i care nu sunt adiacente lui.
nchiderea tranzitiv este :
Figura 12. nchiderea tranzitiv a grafului din figura 9
Ordinul de complexitate al acestei operaii este foarte mare, i anume O (n
3
), pentru c pentru fiecare dintre cele n noduri se aplic
traversarea n adncime, care are complexitatea maxim O (n
2
). Dei este uor de implementat, pentru un graf foarte mare metoda
consum multe resurse.
O alt soluie, mai elegant dar cu acelai grad de complexitate, o fost dat de Stephan Warshall. n construirea algoritmului su,
el a plecat de la ideea urmtoare : lund nodurile Ni, Nj, Nk, (cu i,j,k = 1..n i
k j i
) i dac exist arcele Aik i Akj atunci
exist drum de la nodul Ni la nodul Nj, acest lucru nsemnndu-se n nchiderea tranzitiv a matricei de adiacen.
Algoritmul iniializeaz matricea nchiderii tranzitive cu valoarea matricei de adiacen a grafului i pune valoarea 1 pe diagonala
principal (evident exist arc de la un nod la el). n urma a trei cicluri dup variabilele i, j, k (cu i,j,k = 0..n-1), elementele
matricei nchiderii tranzitive A[n][n] iau valoarea 1 dac a[i][k] = a[k][j], adic :

a[i][j] = a[i][k] & a[k][j] ;
Codul surs n C asociat algoritmului este :
const int MaxLungGraf = 25;
void inchidere_tranzitiva(int a[MaxLungGraf][MaxLungGraf],int n)
{
int i,j,k;
int a_tranz[MaxLungGraf][MaxLungGraf];
//creez matricea nchiderii tranzitive iniial, plecnd de la
//matricea de adiacen a grafului
for(i = 0; i<n; i++)
for(j = 0; j<n; j++)
if(i==j)
a_tranz[i][j] = 1;
else
a_tranz[i][j] = a[i][j];
//cercetez perechi de cte 3 noduri i formez matricea
for(i = 0; i<n; i++)
for(j = 0; j<n; j++)
AAA
BBB
CCC
DDD
EEE
FFF
AAA
BBB
CCC
DDD
EEE
FFF
777
222
333
444
222
222
999
888
111
20 22
AAA
BBB
CCC
DDD
EEE
FFF
777
222
333
444
222
222
999
888
111
20 22
E(A)=0 EE
E(C)=2
L(C)={ A } LL
E(E)=4
L(E)={ A, C } LL
E(B)=5
L(B)={ A, C } LL
E(F)=13 EE
E(D)=infinit EE
L = { A, C, E, B } LL
AAA
BBB
CCC
DDD
EEE
FFF
777
222
333
444
222
222
999
888
111
20 22
E(A)=0 EE
E(C)=2
L(C)={ A } LL
E(E)=4
L(E)={ A, C } LL
E(B)=5
L(B)={ A, C } LL
E(F)=10
L(F)={ A, C, B, D} LL
E(D)=9
L(D)={ A, C, B } LL
L = { A, C, E, B, D, F} LL
for(k = 0; k<n; k++)
a_tranz[i][j] = a_tranz[i][k] && a_tranz[k][j];
//afiez matricea de adiacen a grafului
for(i = 0; i<n; i++)
{
for(j = 0; j<n; j++)
cout << a_tranz[i][j] << " ";
cout << endl;
}
}
5. Problema drumului de lungime minim n graf
Revenim la problema iniial, cea a parcurgerii traseului Arad Bucureti avnd cel mai mic cost. Soluia const n gsirea acelor
orae prin care trece traseul astfel nct suma distanelor parcurse s fie cea mai mic, n raport cu lungimea altor posibile drumuri
de parcurs. La nivelul grafului n loc de orae, distane avem noduri i arce cu greutate.
Parial, problema este rezolvat deoarece folosind cele dou metode de traversare a unui graf avem capacitatea de a afla ce noduri
se afl pe trase i astfel putem forma o serie de drumuri de urmat. Nu mai rmne dect s vedem n cazul grafului cu greutate
care drum are suma valorilor arcelor minim sau n cazul grafului fr greutate care drum are mai puine arce. Dei aceast soluia
este simplu de implementat, ea este mare consumatoare de resurse n cazul unui graf mare, aa c ne trebuie un program care s
combine cele dou etape, reducnd traversrile repetate ale grafului la 1.
Acest lucru este fcut de algoritmul Dijkstra, care examineaz toate drumurile ce pornesc din nodul curent, actualiznd distanele
dintre el i celelalte noduri. Pentru a pstra nodurile prin care trece drumul cel mai scurt, programul le reine ntr-o list pe care o
notm cu L. n final lista conine mulimea minim de noduri care s le conin pe toate cele care vor forma efectiv drumul optim.
Nodurile care se adaug n aceast list sunt acele noduri ale grafului la care se ajunge prin arce directe doar de la nodurile din
lista L ( ele reprezint nodurile adiacente celor din L ) i care au lungimea cumulat pn n acel moment minim.
Pentru a nu calcula de fiecare dat distana minim pn n acel nod, ea este atribuit ca informaie nodului, asemenea unei
etichete. Ele sunt implementate utiliznd un vector de lungime n, unde n este numrul de noduri al grafului (vector[i] reine
eticheta nodului i), sau crend o list cu n elemente de tip etichet.
Drumul minim este gsit n momentul n care n lista L se afl nodul destinaie.
Algoritmul const n paii:
Pasul 1. Se construiete lista L i elementele vectorului/listei distanelor sunt iniializate cu o valoare foarte mare;
Pasul 2. Se alege nodul surs, el devenind i primul nod pus n lista L. Valoarea etichetei corespunztoare lui ia valoarea 0;
Pasul 3. Se repet pn cnd nodul destinaie se afl n L. Sunt analizate nodurile grafului care nu sunt n lista L:
Dac exist noduri Ni n care se poate ajunge prin arce directe de la noduri din L, se calculeaz distana de la nodul de start pn la
ele.
distana(Ni) = min ( val_etichet(Ni) , val_etichet(Nk) + greutate_arc(Nk , Ni) )
unde:
- val_etichet(Ni) reprezint valoarea etichetei asociat nodului Ni;
- greutate_arc( Nk , Ni )) reprezint valoarea arcului dintre nodurile Nk i Ni;
- Nk este un nod din lista L de la care se ajunge prin arc direct la nodul Ni care nu se afl n list;
Se adaug la lista L acel nod Ni care are distana(Ni) obinut minim. Pentru el ca i pentru celelalte noduri pentru care s-au
calculat distanele se reactualizeaz etichetele.
val_etichet(Ni) = min ( val_etichet(Ni) , distana(Ni) )
Dac nu exist nici un nod de acest tip atunci nu exist nici un drum pn la destinaie.
Pasul 4. Dac nodul destinaie se afl n lista L, atunci valoarea etichetei sale reprezint drumul de lungime minim. Pentru
gsirea acestui drum, se pornete napoi de la nodul final i folosind nodurile din L.
Pentru a nu pierde timp la Pasul 4 reconstituind drumul, aa cum s-a ataat fiecrui nod o etichet, i se asociaz o list n care sunt
memorate nodurile precedente care au dat valoarea etichetei n acel moment. Nodul nou introdus n lista L, iniializeaz lista
drumului deja parcurs cu valorile din lista predecesorului su direct i apoi l adaug i pe acesta.
Figura 13 Graf orientat cu greutate
AAA
BBB
CCC
DDD
EEE
FFF
777
222
333
444
222
222
999
888
111
20 22
AAA
BBB
CCC
DDD
EEE
FFF
777
222
333
444
222
222
999
888
111
20 22
E(A)=0 EE
E(C)=2
L(C)={ A } LL
E(E)=4
L(E)={ A, C } LL
E(B)=5
L(B)={ A, C } LL
E(F)=13 EE
E(D)=infinit EE
L = { A, C, E, B } LL
AAA
BBB
CCC
DDD
EEE
FFF
777
222
333
444
222
222
999
888
111
20 22
E(A)=0 EE
E(C)=2
L(C)={ A } LL
E(E)=4
L(E)={ A, C } LL
E(B)=5
L(B)={ A, C } LL
E(F)=10
L(F)={ A, C, B, D} LL
E(D)=9
L(D)={ A, C, B } LL
L = { A, C, E, B, D, F} LL
Pentru a exemplifica metoda, se aplic algoritmul lui Dijkstra pentru a calcula drumul minim de la nodul A la nodul F, noduri ce
aparin grafului din figura 13.
Se fac notaiile ajuttoare : E(Ni) reprezint valoarea etichetei nodului Ni; L(Ni) reprezint lista nodurilor prin care s-a ajuns la
nodul Ni; L reprezint lista nodurilor care au fost luate n considerare.
Etapele parcurse sunt :
- se iniializeaz eticheta nodului A cu valoarea 0, E(A) = 0, iar pentru celelalte noduri cu o valoare foarte mare, E(B) = E(C)
= E(D) = E(E) = E(F) =

. Se pune nodul A n lista L;


- se calculeaz valoarea etichetei vecinilor nodului A, E(B) = 7 i E(C) = 2. Cum nodul C are valoarea etichetei minim i nu
se afl n lista L, el este adugat la aceasta. n lista nodurilor precedente lui C, L(C), se pune nodul A, iar L = { A, C };
- se calculeaz valoarea etichetelor vecinilor nodului C, E(B) = 5 i E(E) = 4. Vechea valoare al lui E(B), care este 7, este
nlocuit de noua valoare calculat, aceasta din urm fiind mai mic. Cum nodul E are eticheta minim i nu se afl n lista L,
este adugat la aceasta i L(E) = { A, C }, iar L = { A, C, E };
- se calculeaz etichetele pentru nodul F care este vecinul direct al nodului E, E(F)=13. Dintre toate etichetele, cea a nodului
are valoarea minim, 5, i cum el nu este n L, este pus n aceast list, deci L = { A, C, E, B }. n lista predecesorilor si sunt
pui predecesorii nodului de la care s-a ajuns la B, adic ai nodului C, i acesta din urm, L(B) = { A, C };
- se calculeaz valoarea etichetelor vecinilor nodului B, E(D) = 9, E(E) = 13 i E(F) = = 25. n cazul nodurilor E i F etichetele
i pstreaz vechile valori, care sunt mai mici. Cu toate c n acest moment nodul E are eticheta cu valoare minim, el nu
este ales ca fiind urmtorul nod al drumului pentru c se afl deja n lista L. Deci nodul care se traverseaz este D, iar L(D) =
{ A, C, B } i L = { A, C, E, B, D };
- se calculeaz valoarea etichetei pentru nodurile E i F (sunt noduri adiacente directe pentru nodul D), E(E) = 11 i E(F) = 10.
Pentru nodul E valoarea etichetei nu este nlocuit cu cea nou. Nodul care nu se afl n lista L i care are valoarea etichetei
minim este F. Este adugat la list i n acest moment cutarea ia sfrit. Drumul minim este A C B D F.
Afiarea drumului minim i a lungimii sale folosind funcia din clasa graf_liste are codul surs :
int lungime = x.drum_minim(g,start,stop,precede);
if(test != MAXINT)
{ cout<<endl<<"Drum minim "<<stop<<"<-"<<start<<" are lungimea : "<<lungime<<" si este : ";
for(int i=stop;i>0&&(i !=MAXINT);i = precede[i]) cout<<i<<"<-";
}
else cout<<"Nu exista drum de la nodul "<<start<<" la nodul "<<stop;
6. Operaii de concatenare i deconcatenare cu grafuri
Definesc concatenarea a doua grafuri ca fiind operaia de adugare a altui graf la unul din nodurile grafului iniial respectnd
urmtoarele reguli:
- Nodul capt al grafului al doilea se va lega printr-un arc de un nod al primului graf. Arcul este orientat pe direcia nod graf 1
->capt graf 2.
- Se introduce de la tastatur informaia nodului unde se va aduga graful al doilea.
AAA
BBB
CCC
DDD
EEE
FFF
777
222
333
444
222
222
999
888
111
20 22
E(A)=0 EE
E(C)=2
L(C)={ A } LL
E(E)=4
L(E)={ A, C } LL
E(B)=5
L(B)={ A, C } LL
E(F)=13 EE
E(D)=infinit EE
L = { A, C, E, B } LL
AAA
BBB
CCC
DDD
EEE
FFF
777
222
333
444
222
222
999
888
111
20 22
E(A)=0 EE
E(C)=2
L(C)={ A } LL
E(E)=4
L(E)={ A, C } LL
E(B)=5
L(B)={ A, C } LL
E(F)=10
L(F)={ A, C, B, D} LL
E(D)=9
L(D)={ A, C, B } LL
L = { A, C, E, B, D, F} LL
- Dac nodul capt al grafului 2 este nod n graful 1 i concatenarea se face n acel nod nu se va mai face nici un arc,
completndu-se lista de arce a nodului din graful 1 cu arcele nodului din graful 2.
- Dac nodul final al grafurilor difer, atunci ntre nodul final al grafului 2 i cel al primului graf se va forma un arc a crui
informaie se va citi de la tastatur.
- Dac al doilea graf se leag la nodul final al grafului 1 atunci nodul final al grafului 2 devine nod final al noului graf obinut
prin concatenarea celor dou grafuri.
- Dac n graful al doilea se afl minim 2 noduri care se afl i n primul graf, o condiie esenial de a face concatenarea celor
dou grafuri este c, dac exist n ambele grafuri arc n acelai sens ntre cele dou noduri, acesta s aib aceeai greutate.
Funcia care verific aceast ultima condiie este urmtoarea:
int verificare(nodgraf *cap,nodgraf *cap2)
{
nodgraf *p,*q,*aux1,*aux2;
int k=1;
for(p=cap;p!=NULL;p=p->next)
for(q=cap2;q!=NULL;q=q->next)
{
if (q->info==p->info)
// vd care noduri sunt comune grafurilor
for(aux1=cap;aux1!=NULL;aux1=aux1->next)
/*nodurile comune le compar 2 cte 2 s vd care este greutatea arcului dac exist vreunul*/
for(aux2=q->next;aux2!=NULL;aux2=aux2->next)
{
if(aux2->info==aux1->info)
if (verif_arc(p,aux1)!=verif_arc(q,aux2))
{ //dac au greutate diferit atunci
printf("\n Nu se poate face concatenarea !");
k=0;
return k;
}
}
}
return k;
}

Funcia care realizeaz concatenarea celor dou grafuri primete ca date de intrare doi pointeri la capetele celor dou grafuri i
returneaz 0 dac nu se poate face concatenarea i l dac a reuit. Funcia respectnd condiiile de mai sus, adaug la lista
nodurilor grafului 1 i nodurile care nu sunt comune ale grafului 2, iar listele de arce ale acestor noduri sunt i ele copiate. n cazul
nodurilor comune, listele arcelor sunt doar completate cu arce noi. Exist i cazuri cnd este nevoie s se creeze arce noi (cnd se
leag de exemplu nodurile finale ale grafurilor) iar atunci greutatea lor este citit de la tastatur.
Funcia este:
int concatenaregraf(nodgraf *cap,nodgraf *cap2)
{
int k;
nodgraf *p,*q,*aux,*ultim1,*ultim2;
arc *r;
//verifica dac se poate face concatenarea
if(verificare(cap,cap2)==0) return 0;
printf("\n La ce nod are loc concatenarea ?");
/*se introduce nodul unde se face concatenarea i se verific dac el exist n primul graf*/
k=citire();
ultim1=cauta_nodgraf_final(cap);
// memorez ultimul nod al grafului 1
ultim2=cauta_nodgraf_final(cap2);
//memorez ultimul nod al grafului 2
/*se insereaz n lista nodurilor primului graf nodurile necomune din al doilea graf*/
for(q=cap2;q!=NULL;q=q->next)
{
p=cauta_nodgraf(cap,q->info);
if(p==NULL) cap=ins_nodgraf(cap,q->info);
}
/* se copiaz pentru noduri i lista arcelor, iar pentru acele noduri care existau se completeaz aceast list*/
for(q=cap2;q!=NULL;q=q->next)
{
p=cauta_nodgraf(cap,q->info);
if(p!=NULL) for(r=q->capat;r!=NULL;r=r->next_arc)
/*functia ins_arc(nod cap,int surs,int destinaie,int greutate) insereaz un nou arc catre nodul cu informaia destinaie de greutate
greutate n lista arcelor nodului cu informaia surs din graful cu capt cap */
ins_arc(cap,p->info,r->destinatie->info,r->weight);
}
/* dac nodul unde se face concatenarea nu este capt al grafului 2 atunci se face arc ntre cele dou cu citirea informaiei de la
tastatur*/
if(cap2->info!=aux->info)
{
printf("\n Distanta dintre nodul ales si capatul grafului 2 este ?");
k=citire();
ins_arc(cap,aux->info,cap2->info,k);
}
/* dac al doilea graf nu se leag la nodul final al primului graf i dac nodurile finale nu sunt aceleai, atunci ele se leag printr-
un arc */
if(aux->info!=ultim1->info)
if(ultim1->info!=ultim2->info)
if(cauta_nodgraf(cap,ultim2->info)==NULL)
/* funcia cauta_nodgraf(nod * cap,int k) cauta un nod cu informaia k n graful cu capt cap, returnnd adresa nodului sau NULL
*/
{
printf("\n Distanta dintre nodul final al grafului 2 si cel al lui 1 este ?");
k=citire();
//se creaz arc intre nod final al grafului 1 si cel al grafului 2
ins_arc(cap,ultim2->info,ultim1->info,k);
}
return 1;
}

Pentru a exemplifica procesul de concatenare a dou grafuri lum grafurile :


7 1
9
8

5 3
0
1
2
3 4
Graf 1




4 6
2 5 6
Graf 2



7 1
9
8
10
5 3

4
6

0
1
2
3 4
6
5
Figura 14. Concatenarea a dou grafuri
Dac se dorete concatenarea grafului 2 la graful 1 n nodul cu valoare 2 atunci graful care va rezulta va fi:
Informaia arcului dintre nodul cu informaia 6 i cel cu informaia 4 a fost introdus de la tastatur fiind ceruta de funcia de
concatenare.
Deconcatenarea unui graf este operaia de rupere a acestui graf n doua grafuri diferite din punct de vedere al nodurilor care le
formeaz i al arcelor ce le leag.
Funcia care realizeaz deconcatenarea grafului primete ca date de intrare pointer la captul grafului de deconcatenat i ea va
returna n pointer la captul celui de-al doilea graf.
n momentul lansrii n execuie se cere s se introduc informaia nodurilor care formeaz al doilea graf. Astfel se va crea lista
nodurilor noului graf care se va obine. Primul lucru care se face dup aceasta este crearea listelor de arce pentru aceste noduri.
Pentru fiecare nod al noului graf se verific dac el are arce cu nodurile acestui nou graf cu ajutorul funciilor:
/*funcia verific dac nodul referit prin *s are arc ctre nodul referit prin *d, i ntoarce ca rezultat greutatea arcului sau 0 dac nu
este arc*/
int verif_arc(nodgraf *s,nodgraf *d)
{
arc * p,*aux;
int gasit=0;
for(p=s->capat;p!=NULL;p=p->next_arc)
if(p->destinatie==d) {
gasit=1;
aux=p;
return aux->weight;
}
if (gasit==0) {
return 0;
}
else return aux->weight;
}
/* funcia primete ca date de intrare pointer la captul grafului i informaia nodului pe care l caut i va returna adresa nodului
cutat sau NULL*/
nodgraf *cauta_nodgraf(nodgraf * cap,int info)
{
nodgraf *p,*q;
int gasit=0;
for(p=cap;p!=NULL;p=p->next)
if(p->info==info) {
gasit=1;
q=p;
}
if(gasit==0){
return NULL;
}
else return q;
}
Odat creat lista nodurilor noului graf i a listelor de arce asociate acestora, voi reactualiza lista nodurilor i a arcelor grafului
iniial. Pentru a realiza acest lucru trebuie respectate urmtoarele lucruri:
- Nodurile celui de-al doilea graf care se formeaz i care sunt surs sau destinaie n arce numai cu noduri care formeaz i
ele al doilea graf, sunt terse dintre nodurile grafului iniial.
- Nodurile grafului care se formeaz i care sunt i surs i destinaie n arce cu noduri care nu intr n al doilea graf rmn n
primul graf, dar se terg arcele cu nodurile care nu rmn.
Funcia care verific dac un nod respect aceast condiie sau nu este :

/* funcia primete ca date de intrare referine la captul grafului iniial, la al celui nou i la nodul care se verific ; ea va returna 0
dac nu are legtur cu noduri care rmn n graful iniial i o valoare diferit de 0 n caz contrar*/
int verif_stergere(nodgraf *cap,nodgraf *cap2,nodgraf *q)
{
nodgraf *p,*z;
int k=0;
int vb=0;
for(p=cap;p!=NULL;p=p->next)
{
if(cauta_nodgraf(cap2,p->info)==NULL)
{
z=cauta_nodgraf(cap,q->info);
if(z!=NULL) k=verif_arc(p,z);
if(k!=0) vb=k;
}
}
return vb;
}
Funciile care realizeaz deconcatenarea unui graf sunt:
/* functia se apeleaz dupa funcia deconcatengraf i are ca scop reactualizarea listei de noduri a grafului iniial */
/*primeste ca date de intrare referinta la capetele celor doua grafuri*/
void stergerenodgrafuri(nodgraf *&cap,nodgraf *cap2)
{
int t;
nodgraf *p,*q,*z,w;
for(p=cap;p!=NULL;p=p->next)
for(q=cap2;q!=NULL;q=q->next)
{
z=cauta_nodgraf(cap,q->info);
if(z!=NULL)
if(z->capat==NULL) sterg_arc(p,z);
else
{
t=verif_stergere(cap,cap2,q);
if(t==0) {
z->capat=NULL;
}
}
}
for(q=cap2;q!=NULL;q=q->next)
{
p=cauta_nodgraf(cap,q->info);
if(p!=NULL)
if(p->capat==NULL) cap=sterg_nodgraf(cap,p->info);
}
}
/* realizeaz deconcatenarea grafului iniial crend un nou graf*/
/* primete ca date de intrare referinta la captul primului graf i ntoarce adresa captului noului graf*/
nodgraf *deconcatengraf(nodgraf * &cap)
{
nodgraf *cap2,*p,*q,*w,*z;
arc *r;
int k,nd,arc;
cap2=NULL;
/*citete de la tastatur informaia nodului capt al noului graf*/
printf("\n Nodul capat al grafului al 2-lea este :");
k=citire2(&nd,cap,MAX);
/*odat citi informaia este creat i inserat un nod cu aceast informaie n lista de noduri */
cap2=ins_nodgraf(cap2,nd);
if(k==0)
{
printf("\n Urmatoarele nodgrafuri sunt:");
Memoria
extern ee
Operaii de
citire / scriere cccccc
adresa de nceput
buffer bb
zona de memorie
definit de
utilizator uu
666
111
555
222
333 444
k=citire2(&nd,cap,MAX);
cap2=ins_nodgraf(cap2,nd);
//se creaz i celelalte noduri
while(k==0)
{
k=citire2(&nd,cap,MAX);
cap2=ins_nodgraf(cap2,nd);
}
}
/* n secvena urmtoare se creeaz listele de arce ale nodurilor noului graf ; se parcurge lista nodurilor iniiale verificndu-se care
se afl n noul graf ; dac se gsete un astfel de nod se verific dac are arce cu alte noduri ale noului graf ; cnd se gsesc aceste
arce, ele se scriu n noul graf i se terg din graful iniial din listele acelor noduri*/
for(p=cap2;p!=NULL;p=p->next)
{
q=cauta_nodgraf(cap,p->info);
//caut echivalentul lui n graful iniial*/
for(z=cap2;z!=NULL;z=z->next)
{
w=cauta_nodgraf(cap,z->info);
arc=verif_arc(q,w);/* funcia verific dac exist arc intre nodurile cu adresele q i w*/
if(arc!=0) {/*dac se gsete arc se scrie n graful nou i se terge de aici*/
ins_arc(cap2,q->info,w->info,arc);
sterg_arc(q,w);
}
}
}
return cap2;//returneaz adresa nodului capt a noului graf
}
Pentru a exemplifica deconcatenarea lum urmtorul graf:
1 2 6

3 5

11

4
0 1
3
2
4
5
1 2 6
0 1 2 5
Graful rmas

3 4
2 3 4
Noul graf
Figura 15. Deconcatenarea unui graf.
Dac se deconcateneaz graful format din nodurile 2, 3 i 4 atunci vom obine grafurile din Figura 14.
Memoria
extern ee
Operaii de
citire / scriere cccccc
adresa de nceput
buffer bb
zona de memorie
definit de
utilizator uu
666
111
555
222
333 444
10. FIIERE
10.1. Structuri de date externe
Masivele, listele i arborii binari, sunt structuri de date interne, prin faptul c se afl n memoria intern a unui sistem de
calcul. n momentul n care aceste structuri vor fi stocate n memoria extern pe discuri, pe benzi magnetice sau pe diskete,
acestea vor fi numite structuri de date externe.
Memoria intern a unui calculator este imaginat ca un ir ordonat de baii. Fiecare bait se definete prin adres i prin
coninut. Memoria extern este imaginat, de asemeni, ca un ir de baii, cu deosebirea c, pentru calculul adresei sunt luate n
considerare elementele specifice modului de structurare a suportului.
Astfel, atunci cnd suportul este organizat n piste, cilindri i problematica accesului este rezolvat prin poziionarea pe
aceste uniti de acces, adresarea efectundu-se lund n calcul elemente structurale.
n plus, particularitile de desfurare n plan fizic a operaiilor de intrare / ieire, determin analiza distinct a raportului
dintre semnificaia instruciunilor READ / WRITE din programe i operaiile efective de citire / scriere de pe suportul extern.
Presupunnd c pentru un sistem de calcul, modulele care realizeaz citiri / scrieri, opereaz cu coninutul unor zone
(buffere) de lungime L, tot timpul aceste funcii vor furniza informaii asupra nceputului zonei ce este explorat, lungimea
acesteia fiind rezultatul logicii de organizare a datelor.
Programatorul are acces direct sau indirect la zona de memorie tampon (buffer), prin intermediul adresei sale de nceput,
sau prin intermediul unei alte zone de memorie definit n programul sau, zon n care este copiat coninutul bufferului.
Dinamica operaiilor de intrare / ieire, determin actualizarea variabilei pointer, care delimiteaz partea de nceput a
subzonei din buffer ce este copiat n zona de memorie definit de utilizator.
n cazul funciilor de citire / scriere a unui caracter, variabila pointer se modific cu o unitate, marcnd exact schimbul de
informaii n dialogul om calculator .
n cazul citirilor / scrierilor cu format, delimitatorul acceptat ca regul al fiecrui cmp, este analizat i algoritmul de
punere n coresponden, este astfel proiectat nct acesta nu este integrat n setul informaiilor.
1 5 CR 1 2 0 CR 1 CR 1

CR
algoritm
conversie
alfanumeric
- - > ntreg
algoritm
conversie
alfanumeric
- - > ntreg
algoritm
conversie
alfanumeric
- - > ntreg
algoritm
conversie
alfanumeric
- - > real
variabila A variabila B variabila C variabila D
Memoria
extern ee
Operaii de
citire / scriere cccccc
adresa de nceput
buffer bb
zona de memorie
definit de
utilizator uu
666
111
555
222
333 444
irurile de caractere sunt delimitate prin <CR>, iar algoritmul de parcurgere a bufferului, determin un astfel de coninut
al variabilei pointer, nct este transmis ca parametru funciilor de conversie, exact nceputul fiecrei subzone de buffer care
ncepe dup <CR>.
Modul cum este concretizat <CR> ca delimitator de sfrit de ir i modul cum este definit descriptorul de format,
imprim structurii de parametri ai funciilor de conversie anumite particulariti.
Se observ c dinamica variabilei pointer, este influenat de tipul operaiei de intrare / ieire. Acest aspect explic de ce
este necesar efectuarea avansului acestuia, cnd se alterneaz citiri cu format, cu citiri fr format. La operaii neomogene, exist
modaliti neomogene de definire i de tratare a delimitatorilor de sfrit de ir, ca rezultat al activrii tastei <CR>.
Ceea ce pare simplu n cazul structurilor de date interne, nu devine mai complicat n cazul structurilor de date externe,
att timp ct sunt clarificate chestiunile legate de variabilele pointer asociate bufferelor i de faptul c o citire fizic, efectiv nu
nseamn neaprat o citire logic, iar la scriere se ntmpl acelai lucru. Prin operaia logic, nelegem aciunea ce corespunde
unei apelri de funcie citire / scriere din program.
De exemplu, pentru zona de lungime minim L = 256, ce este scris / citit la o singur operaie fizic, efectiv, pe / de
pe suport, dac dorim s scriem pe suportul extern trei variabile de tip articol, A, B i C cu lg ( A ) = 120, lg ( B ) = 110, lg ( C ) =
200 baii, variabila pointer permite preluarea datelor din structura A, se majoreaz cu 120, preia datele din structura B i realizeaz
o scriere fizic pe suport. Variabila pointer este apoi reiniializat i va prelua datele structurii C dup care efectueaz a doua
scriere fizic. n acest caz celor trei scrieri logice le-au corespuns dou scrieri fizice.
Exist diferite modaliti de realizare a operaiilor de citire / scriere, dup cum se folosesc sau nu factori de blocare, se
definesc sau nu elemente de regsire a informaiilor.
Structurile de date externe, nu difer mult de structurile de date interne. Apar unele complicaii, care nu sunt majore de
altfel, prin aceea c volumul datelor este foarte mare i elementele repetitive abund, ceea ce conduce la ideea c structurile de
date externe, sunt privite ca structuri de structuri de date interne dispuse pe suport de memorie extern.
Pentru a realiza regsirea ntr-un volum de date de dimensiuni remarcabile, este necesar organizarea (sistematizarea)
datelor i crearea acelor elemente indispensabile localizrii (adresrii).
Structurile de date externe sunt contigue, formate din elemente unele dispuse n continuarea celorlalte i necontigue,
distana dintre elemente fiind o variabil aleatoare a crei lege de repartiie este identificabil, dar care necesit memorarea
distanelor, ntruct nu se construiete un mecanism de generare cu repetare a acestora.
Structurile de date externe, se regsesc n cele mai multe cazuri sub denumirea de fiiere. Cnd ating un nivel de
structurare prin adrese suficient de dezvoltat, se formeaz fiiere iterdependente, iar n cazul unor structuri mai complexe, se
regsesc sub denumirea de baze de date.
n cazul n care coninutul de lungime L este tratat distinct, se ia n discuie conceptul de nregistrare fizic. Se pornete
de la faptul c ntr-un buffer, de regul sunt stocate datele ce corespund unei structuri de tip articol (STRUCT), ce se recunosc n
folclorul informatic, sub denumirea de nregistrare logic sau articol logic, tocmai pentru a face deosebirea ntre modul n care
se dispun informaiile pe suportul fizic i modul n care sunt gndite organizrile de date n raport cu prelucrrile particulare.
Introducerea factorilor de blocare vine s complice lucrurile, dar s mbunteasc indicele de folosire a zonelor de
memorie.
Dac:
L = lg (structura de date de tip articol) < L
i dac exist:
1
]
1

' L
L
k
unde parantezele drepte nseamn partea ntreag a expresiei, raportul k reprezint o expresie mai simplificat a factorului de
blocare.
De exemplu, dac definim o structur de tip articol, ce conine cmpuri ce conduc la o lungime de 80 baii i L = 256,
[ ] 3 2 , 3
80
256

1
]
1

k
n cazul n care k = 1, pe cei 256 baii ai bufferului este ncrcat un articol, ce este n fiier. Deci fiierul conine n final
n articole fizice i tot n articole logice, gradul de ncrcare cu informaie util fiind:
% 30 100
32
10
100
256
80
1

n
n
g
n cazul n care k = 2,
[ ] [ ]
100
256
160 2 /
2

n
m n
g

'

impar numar e n daca


par numar e n daca
m
1
0
Pentru k = 3,
[ ] [ ]
100
256
240 3
3

n
m n
g
Se observ c:
1 2 3
g g g
Se vorbete de factorul de blocare optim, care se stabilete pentru fiecare tip de memorie extern i lungime de structur
de date de tip articol, ce urmeaz a fi memorat n fiier.
n continuare, lund n considerare numai aspectele care in de modul de stocare a informaiei, strict dependent de
aplicaia programatorului, se vor face urmtoarele specificaii:
- se consider fiierul ca structur de date contigu, dac informaiile utile sunt dispuse unele n continuarea celorlalte, fr baii
care s le separe;
- se consider fiierul ca structur de date regulat necontigu, dac ntre toate articolele, sau ntre grupuri (buchete) de articole,
avnd numr fix, exist baii nefolosii, n acelai numr; exist posibilitatea de a construi o formul de calcul a adresei articolului
k, pornind de la adresa altui articol j;
- se consider structuri de date necontigue, fiierele ale cror elemente (articole) sunt dispuse unele fa de celelalte, la distane
care sunt variabile aleatoare.
Trecerea de la memoria intern la memoria extern, ia n considerare modul de organizare al fiecrui support. Dac la
nivelul memoriei interne aceasta este privit ca un ir (vector), n cazul suporturilor externe de informaie organizate pe piste,
baiii sunt privii ca avnd dispunerea asemeni elementelor unei matrice; linia indic pista pe care se afl baitul, iar coloana indic
poziia baitului pe pist.
Organizarea pe sectoare, determin luarea n considerare a unei matrice tridimensionale. Pentru fiecare suport,
realizatorii pun la dispoziie formulele de calcul ale adreselor, cu luarea n considerare a elementelor de structur a suportului
fizic.
Problema fragmentrii informaiilor, determin stocarea de date necesare localizrii prii ce se continu ntr-o alt zon
a suportului.
Pentru simplificarea prezentrii, se consider un suport extern S, cruia i se asociaz un model matriceal de dispunere a
baiilor. Baitul bij reprezint baitul al j-lea, aflat pe pista i a suportului. Suportul are n piste, iar pe o pist se afl m baii.
Pentru nceput presupunem ca baiii au aceeai destinaie, de a memora informaii utile. Nu exist baii care stocheaz
informaii privind structura suportului i modul de ocupare a acestuia.
10.2. Criterii de clasificare a fiierelor
i n cazul clasificrii fiierelor, asemeni datelor interne, exist o multitudine de criterii, fiecare fiier putnd fi clasificat
cu unul sau mai multe atribute ce corespund criteriilor de clasificare.
a) Criteriul lungimii articolelor ce alctuiesc fiierul, le mparte n:
- fiiere cu articole de lungime fix; aceste fiiere sunt formate din elemente (articole) avnd aceeai lungime; fiierele
sunt asemntoare vectorilor ca structuri de date interne; elementele sunt omogene i sunt dispuse unele n continuarea celorlalte;
- fiierele cu articole de lungimi diferite, dar cunoscute; se consider m tipuri de articole, avnd fiecare lungimea 11, 12,
, 1m; fiierul conine aceste elemente dispuse ntr-o anumit ordine, sau n ordine oarecare; n aceast ultim situaie este
necesar memorarea de informaii care s permit identificarea tipurilor de articole i lungimea acestora;
- fiiere cu articole de lungime diferit, dar necunoscut; ceea ce se cunoate este legat de faptul c lungimile articolelor
se afl cuprinse ntre dou limite: lungimile articolelor sunt variabile aleatoare, aparinnd unui interval definit; n mod obligatoriu
primul cmp conine lungimea articolului;
b) Criteriul informaiilor ce definesc regulile referitoare la dispunerea elementelor, mparte fiierele n:
- fiiere avnd ca singur mod de dispunere, poziia articolelor;
- fiiere cu elemente sortate dup un cmp numit cheie a articolului, dup care se face reperarea n fiier;
c) Criteriul informaiilor de localizare a elementelor (articolelor) ce alctuiesc fiierul;
- fiiere care nu conin informaii asupra poziiei articolelor; singura modalitate de a selecta un articol, este parcurgerea
tuturor articolelor care l preced;
- fiiere care au definite zone ce conin informaii referitoare la adresele unor grupe i subgrupe de articole; pentru a
identifica un anumit element, se localizeaz grupul i apoi subgrupul de articole; odat identificat subgrupul, selectarea
elementului cutat este rezultatul parcurgerii articol de articol pn la gsirea respectivului element;
- fiiere n care elementele (articolele), conin informaii ce permit conturarea de liste nlnuite sau arbori, pe supori de
memorie extern; compexitatea legturilor dintre elementele (articolele) fiierului, determin un volum de informaie privind
adresele articolelor cu care un element intr ntr-o anumit relaie;
d) Criteriul operaiilor ce sunt efectuate de fiiere, determin gruparea acestora n:
- fiiere destinate scrierii datelor;
- fiiere destinate citirii datelor;
- fiiere destinate efecturii operaiilor de actualizare; Oricare dintre fiierele unei grupe, n raport cu scopurile prelucrrii
ce determin i modific atributele. De exemplu, un fiier care va fi creat, este destinat scrierii datelor. Acelai fiier la
consultare, aparine grupei a doua, iar dac naintea consultrii se efectueaz actualizri, acelai fiier aparine celei de a treia
grupe.
e) Criteriul gestiunii fiierelor, ia n considerare existena unui sistem de funcii de prelucrare, care asigur efectuarea operaiilor
specifice lucrului cu fiiere, numit sistem de gestiunea fiierelor; acest criteriu mparte mulimea fiierelor n:
- fiiere care sunt prelucrate prin apelarea de funcii ale unui sistem de gestiune, care rezolv ntreaga problematic legat
de organizarea i accesul la date; funciilor sistemului de gestiune a fiierelor, le vor corespunde n limbajele de programare
evoluate instruciuni; parametrii instruciunilor devin parametrii reali ai funciilor sistemului de gestiune; programatorul
abordeaz ntreaga problematic numai din punct de vedere logic al rezolvrii problemei sale;
- fiiere pentru care sunt definite funcii primitive de realizare a operaiilor elementare cu datele destinate suporturilor
externe; programatorului i revine sarcina s gestioneze totalitatea informaiilor necesare regsirii elementelor ce alctuiesc
fiierul; pentru programator, fiierul este o mas amorf de baii, avnd coninut i poziii; programatorul efectueaz transferuri de
baii din zone de memorie spre suportul extern, indicnd adrese acestor zone, lungimea zonei i un mod de reparare a fiierului;
exist situaii n care se efectueaz lucru direct n bufferul asociat fiierului cu care se lucreaz; n acest caz fiierul apare ca o
resurs iar gestiunea acestei resurse este lsat integral la dispoziia programatorului;
- fiiere care se construiesc i se utilizeaz folosind instruciunile limbajului de asamblare; n acest caz programatorul
definete totalitatea condiiilor pentru efectuarea operaiilor cu fiiere; sunt definite i ncrcate etichetele care vor fi scrise; se
definesc bufferele i se gestioneaz; se calculeaz adresele de pe suportul extern unde vor fi scrise datele; programatorul preia n
programele sale tot ceea ce efectueaz funciile primitive sau sistemul de gestiune a fiierelor; programul n care apar fiierele
gestionate de programator, nu apeleaz alte funcii dect cele scrise de acesta i folosete numai instruciuni ale limbajului de
asamblare, cel mult seturi de macroinstruciuni.
f) Criteriul organizrii fiierelor, ia n considerare existena sau inexistena unor informaii de regsire a datelor, dup cum
urmeaz:
- fiierele cu organizarea secvenial, se constituie ca succesiune contigu de elemente (articole), fr existena unor
elemente de informare, altele dect delimitatorii de nceput i de sfrit (etichete); dac se ia n considerare similitudinea acestui
mod de organizare cu nregistrarea pe o caset a lagrelor unei formaii rock, avem imaginea clar a tuturor posibilitilor de
lucru cu fiierele secveniale; accesul la un lagr presupune audierea celor care-l preced; tergerea unui lagr, altul dect cel de
la sfrit presupune existena a dou casete; nregistrarea unui nou lagr, se face numai dup ultimul lagr anterior;
- fiierele nsoite de informaii de tip index, presupun sortarea articolelor dup chei i mprirea acestora n submulimi;
punerea n coresponden a elementelor din submulimi cu adresele fizice, determin realizarea ntr-un fiier a unei mulimi de
subfiiere secveniale; cu ajutorul indecilor se identific subfiierul secvenial i articolul cutat este preluat dup ce a fost
localizat prin parcurgerea articol dup articol a subfiierului, operaiile de actualizare, vizeaz tergerea de articole, adugarea de
articole la sfritul fiierului sau subfiierelor, modificarea de cmpuri, rescrierea de articole i inserarea de articole; subfiierele
sunt masive unidimensionale contigue, formate din articole; tergerea este o operaie de dezactivare a elementelor, fr realizarea
deplasrii celorlalte elemente cu o poziie spre stnga, deci fizic tergerea unui articol nu se produce, operaia fiind numai la nivel
logic, n sensul c accesul la date este precedat de un test asupra caracterului activ sau neactiv al articolului; inserarea de articole,
pentru a menine criteriul ordonrii elementelor care a determinat mprirea mulimii n submulimi de articole, presupune
realizarea de liste nlnuite; articolul inserat este dispus ntr-o zon disponibil numit folcloric, zona de depire.
- fiiere ale cror articole sunt dispuse aleator pe suport; cunoscndu-se dimensiunile fiierului, mai nti acestuia i se
aloc o zon pe suportul extern, printr-o operaie numit preformare; datele ce vor fi stocate n fiiere, sunt puse n coresponden
printr-un procedeu oarecare, cu adresele unde vor fi scrise; rezult c, procedeul de punere n coresponden, este cu att mai
performant, cu ct el realizeaz o dispunere mai uniform a articolelor n zona rezervat; exist posibilitatea ca folosind algoritmi
de randomizare, s se obin elemente ce intr n calculul adresei fizice a nceputului zonei din suportul extern n care se scrie un
articol; pornind de la imposibilitatea ca practic s se genereze prin algoritmi pentru valori de intrare date, numere diferite, care s
ndeplineasc condiia de apartenen la subintervale, pe msur ce se scriu articole n fiiere, are loc frmiarea zonei rezervate;
se construiesc funcii pentru gestionarea articolelor care ar au aceeai adres fizic prin calcul; aceste fiiere cu organizarea
aleatoare, permit efectuarea ntregii game de operaii, cu condiia ca mecanismul de obinere a adresei fizice s se menin
neschimbat; fiierul organizat aleator (random), apare ca o structur necontigu, n care fiecare element este localizat pe baza unei
formule, avnd ca parametru valoarea unui cmp ce intr n structura articolului, cmp numit cheia articolului; numeroasele
lucrri care prezint limbajul COBOL, redau imagini sugestive ale modului n care se implementeaz filozofia fiecrui mod de
organizare a fiierelor, deci realitatea este alta, dac se are n vedere organizarea matriceal a suportului i modul nedinamic n
multe cazuri de alocare a memoriei externe;
g) Criteriul suportului unde este stocat fiierul, mparte fiierele n:
- fiiere pe cartele perforate;
- fiiere pe band perforat;
- fiiere pe band magnetic;
- fiiere pe disc;
- fiiere pe diskete;
- fiier n memoria intern.
Prelucrrile moderne, nengrdite de restriciile lipsei de memorie intern, au condus la citirea unui fiier ca un singur articol
foarte mare i prelucrarea acestuia n memorie. Logic apare o singur instruciune de citire, deci apelarea o singur dat a funciei
n realitate au loc:
m
L
Lf
+
1
]
1

citiri fizice, unde:


Lf lungimea fiierului, dat n baii;
L lungimea unei nregistrri fizice la o citire;
m variabila boolean ce este 0, dac Lf este divizibil prin L i 1 n caz contrar;
h) Criteriul modului de efectuare a operaiilor de intrare / ieire grupeaz fiierele n:
- fiiere de tip stream n care datele la scriere sau la citire, sunt cmpuri elementare sau alte tipuri structuri de date,
constituite ntr-un ir, cu indicarea formatului dup care se fac mai nti conveniile i apoi se stabilesc lungimile irurilor care vor
fi scrise pe suport; fiierul apare ca o succesiune de elemente oarecare, ale cror poziii sunt deduse dac se iau n calcul,
informaiile pe care le ofer descriptorii de format i locul pe care fiecare element l ocup n lista de parametri ai funciei apelate
la scriere, este de dorit ca aceleai liste de variabile de la scriere, s fie utilizate i la apelul funciilor de citire, iar descriptorii de
format s se menin aceeai pentru a oferi succes prelucrrilor:
- fiiere de tip record, n care datele sunt caracterizate prin lungime i adres de nceput; articolele au lungime fix, sau
variabilitatea lungimilor este n cadrul unei mulimi formate din cteva elemente; operaiile de lucru cu fiierele de acest tip, nu
sunt n general precedate sau urmate de conversii; operaiile ce preced calculele, sunt lsate la dispoziia programatorului;
Un fiier oarecare este caracterizat nscriind oricare dintre informaiile ce rezult din criteriile specificate.
Astfel, fiierul stocurilor de materiale, este:
- un fiier de tip record;
- are organizare indexat;
- se afl pe disc;
- este gestionat cu funciile unui sistem de gestiune a fiierelor;
- are articole de lungime fix;
- se efectueaz toate operaiile de actualizare pe el;
- conine informaii asupra poziiei anumitor articole;
- articolele sunt identificate dup codul materialului care joac rol de cheie de articol;
- fiecare material are o cheie unic;
- fiierul este sortat cresctor;
10.3. Fiiere secveniale
Fie mulimea de elemente E1, E2, , En, oarecare, ce corespund structurilor de date S1, S2, , Sn, definite ntr-un program
P.
Elementele Ei, i = 1, 2, , n, sunt iruri de baii caracterizate printr-un coninut rezultat din iniializarea structurilor de
date Si, i = 1, 2, , n. Pe un suport extern, se aloc elementelor E1, E2, , En zone de memorie de lungime
( ) ( ) lg lg + Si
fiierul avnd n final lungimea:
( ) ( )

+
n
i
Si n Lf
1
lg lg
De obicei,
( ) . 2 lg
Cei doi baii ataai fiecrui element vor conine lungimea articolului.
( ) ( ) Si cont lg
Fiierul este caracterizat printr-o adres a articolelor.
Astfel:
( ) ( ) lg 1 + A E adr
unde, A reprezint adresa fizic a primului bait a primului articol, cruia i s-a ataat n fa
( ) lg
baii, pentru a memora
lungimea articolului respectiv.
( ) ( ) ( ) ( )

+ +
1
1
lg
i
j
i j cont A Ei adr
sau
( ) ( ) ( )

+ +
1
1
lg lg
i
j
i Si A Ei adr
unde,
K
B
reprezint grupul de baii de lungime
( ) lg
ataat elementului Ek n fiier.
Dac:
( ) ( ) ( ) Sn S S lg ... 2 lg 1 lg
atunci:
( ) ( ) ( ) n cont cont cont ... 2 1
caz n care, n eticheta de nceput a fiierului se specific tipul articolului lungime fix; tot aici se memoreaz i lungimea,, iar
( ) k lg
devine zero.
Adresa unui element oarecare Ei, este obinut prin relaia:
(Q1, P4) ((
(Q1, P2) (( (Q3, P4) ((
(Q1, P1) (( (Q2, P2) (( (Q3, P3) (( (Q4, P4) ((
( ) ( )

+
1
1
lg
i
j
Sj A Ei adr
Cu fiierele secveniale se efectueaz urmtoarele proceduri:
- crearea unui fiier secvenial const n dispunerea elementelor E1, E2, , En pe suport n aceast ordine;
- consultarea integral sau parial a fiierului, baleiaz (citete) din aproape n aproape elementele fiierului i se prelucreaz
acelea care prezint interes;
- adugarea elementului Em se efectueaz la adresa:
( ) ( ) ( ) ( ) lg lg + + Sn En adr Em adr
ceea ce pune n eviden c, adugarea se face numai la sfritul fiierului;
- intercalarea a dou fiiere;
- sortarea fiierelor, care const n obinerea unui fiier n care articolele au o astfel de dispunere, nct pentru un cmp x s existe
relaia:
cont (E1.x) > cont (E2.x) > > cont (En.x)
dac sortarea s-a fcut descresctor, sau:
cont (E1.x) < cont (E2.x) < < cont (En.x)
dac sortarea s-a fcut cresctor.
ntruct se lucreaz n cele mai multe cazuri cu fiierul n totalitatea lui, nu este justificat memoria de informaii pentru
anumite articole.
Explorarea fiierelor secveniale corespunde unei structuri de date contigue, asemeni unui vector de structur sau a unei
niruiri de diferite structuri, cu posibilitatea calculului adresei unui element oarecare.
adr (suc (Ei)) = adr (Ei) + lg (Si) + lg ()
adr (pred (Ei)) = adr (Ei) lg (Si-1) lg ()
Se spune c fiierul este nchis dac:
( ) En Ei suc
m
m


lim
Se spune c fiierul este deschis dac:
( ) 1 lim E Ei pred
m
m


O astfel de abordare, determin continuarea prelucrrii chiar dac exist tentative de a nchide un fiier deja nchis, sau
de a deschide un fiier deja deschis.
Aici apare o problem n legtur cu parametrii funciei de deschidere. Dac sunt luai n considerare parametrii primei
deschideri, problema este rezolvat, tentativele de deschidere a unor fiiere deja deschise fiind inefective.
ntruct exist formule de calcul pentru adresele fiecrui element din submulimea E1, E2, , En, nu se justific
construirea unui vector a adreselor n fiier (a1, a2, , an) pentru aceste elemente.
Sistemele de operare evoluate gestioneaz nchiderea fiierelor la nchiderea execuiei programelor.
10.4. Fiiere secvenial indexate
Se consider o mulime de elemente E1, E2, , En, generate dup structura S i un cmp X astfel nct:
cont (E1.x) < cont (E2.x) < < cont (En.x)
deci, irul elementelor este sortat cresctor dup cmpul x, care joac rol de cheie a articolelor n structura S de generare.
Elementele de sortare vor fi memorate, fiecare ocupnd o zon de lungime.
( ) ( ) +lg lg S
unde,

reprezint o zon n care este memorat o adres fizic de pe suport, innd seama de structurarea contigu a suportului.
Fiierul are un fond informaional de lungime:
( ) ( ) [ ] S n Lf lg lg +
Se construiete mulimea perechilor:
(cont(Ei.x).ai)
a cheilor i adreselor articolelor ce intr n componena fiierului. Se calculeaz:
( ) ( )
n
x x Ei cont
n
i

1 2
.

(Q1, P4) ((
(Q1, P2) (( (Q3, P4) ((
(Q1, P1) (( (Q2, P2) (( (Q3, P3) (( (Q4, P4) ((
i rezult o mprtiere suficient de mare care s reduc ansele gsirii unei formule de calcul a adresei fizice a unui articol,
folosind strict ca informaie cheia acestuia.
Dac se accept idea utilizrii unui arbore binar cu 4 noduri terminale, mulimea elementelor E1, E2, , En este mprit
n 4 subiruri, avnd un numr aproape identic de elemente, reinnd adrese i cheile elementelor ce delimiteaz fiecare subir de
articole.
(cont(
j
Ek
.x),
j
ak
) j = 1, 2, 3, 4
k = (1, 2, , n)
k1 < k2 < k3 < k4.
Perechile de delimitare ale nceputului de subir, se obin astfel:
- pentru primul subir
( ) ( )
1 1
, . 1 a x E cont Q
- pentru al doilea subir
( ) ( )
1 1
, . 2
+ +

m m
a x E cont Q
- pentru al treilea subir
( ) ( )
1 2 2 1
, . 3
+ +

m m
a x E cont Q
- pentru al patrulea subir
( ) ( )
1 3 3 1
, . 4
+ +

m m
a x E cont Q
Perechile pentru delimitarea sfritului pentru fiecare din cele 4 subiruri sunt, respectiv:
( ) ( )
( ) ( )
( ) ( )
( ) ( )
n n
m m
m m
m m
a x E cont P
a x E cont P
a x E cont P
a x E cont P
, . 4
, . 3
, . 2
, . 1
3 3
2 2

S-a considerat c fiecare subir are m elemente, cu excepia ultimului ir care are 1, 2 sau 3 elemente mai puine.
Setului de date i se asociaz arborele binar:
Dac, de exemplu, fiierul sortat ar fi organizat secvenial i dorim s citim articolul penultim, care are cheia 7233, n
mod normal trebuie s citim cele n-2 articole care l preced. Dac ns fiierul este nzestrat cu aceast informaie pe care o
conine arborele binar cu 4 noduri terminale, inspectarea nodului rdcin ne permite s vedem c articolul cutat cu cheia 7233
este n fiier, adic:
cont (E1.x) < 7233 < cont (En.x)
ntruct:
2
(Ei.x) cont (En.x) cont
7233
+

rezult c se parcurge pe nivelul inferior, nodul din dreapta.


ntruct:
2
(En.x) cont 1.x) (E2n cont
7233
+ +

rezult c se parcurge pe nivelul inferior, nodul din dreapta.


Odat ajungnd pe ultimul nivel al arborescenei, se rein adresele a3m+1 i an i se baleiaz secvenial subfiierul
delimitat astfel. Deci, se vor baleia mai puin din totalul elementelor fiierului.
Pentru construirea arborilor binari asociai, exist numeroi algoritmi de partiionare a fondului informaional. Important
este ca numrul cutrilor secveniale, s fie ct mai redus. Trebuie realizat un echilibru ntre numrul de nivele ale arborelui binar
i numrul subfiierelor, pentru c creterea numrului de subfiiere conduce la creterea duratei de acces la acestea i nu la
reducerea ei, din cauza parcurgerii unui numr prea mare de noduri n arborele binar.
n cazul n care se dorete inserarea unui articol Ej ntr-un astfel de fiier, se identific poziia lui, astfel nct:
cont (Ek.x) < cont (Ej.x) < < cont (Ek+1.x)
(Q1, P4) ((
(Q1, P2) (( (Q3, P4) ((
(Q1, P1) (( (Q2, P2) (( (Q3, P3) (( (Q4, P4) ((
PRODUSE PPProdusul x PP
MATERIALE
Cod mat.1 ..
Cod mat. 2 ..
Cod mat. 3. ..
Cod mat. 4 .. CC
n acest caz, articolul ca atare este memorat ntr-o zon rezervat a fiierului, legtura cu celelalte articole efectundu-se prin:
( ) ( )
( ) ( ) 1 +

Ek adr j cont
Ej adr k cont
ce corespunde unei inserri de elemente ntr-o list.
La un numr mare de inserri, parcurgerea listelor reduce performana programului de exploatare a fiierului secvenial
indexat. Acestea justific trecerea la reorganizarea fiierului. Prin reorganizare, se nelege crearea unui nou fiier, n care
elementele se dispun ntr-o aceeai zon, fr a mai exista informaii de legtur, ca n cazul n care ar fi dispersate pe suport.
La reorganizare, se construiete un nou binar al indecilor. Utilizarea arborilor binari are aici numai un caracter
exemplificativ. Tipul de arbore depinde n principal de mprtierea cheilor n intervalul pe care sunt definite. Informaiile privind
arborele asociat tabelei de indeci, se stocheaz pe suport i face parte din fiier.
Pentru o parcurgere mai rapid, n cazul n care este posibil, informaiile aferente structurii arborescente a indecilor, se
ncarc n memoria intern i se lucreaz cu ele folosind funciile de parcurgere ale unui arbore.
n limbajele precum C i C++, fiecare programator implementeaz algoritmi proprii pentru organizarea secvenial
indexat, iar prin comparaia comportamentului lor statistic cu ali algoritmi existeni, sunt dezvoltai sau abandonai.
10.5. Fiiere aleatoare
Sunt acele fiiere care ocup o anumit zon din memoria extern i ale cror elemente nu sunt reperate dect prin adresa
fizic pe care o au pe suportul extern.
ntruct abordarea fiierelor random, depete prin amploarea fundamentrii acest cadru, se consider oportun
prezentarea unui caz particular de fiiere, ale cror adrese ale elementelor, se calculeaz n funcie de poziia pe care acestea o au,
tot astfel cum se procedeaz n cazul masivelor unidimensionale.
Se consider funcia poz (Em) care indic poziia elementului (Em) n irul de articole.
Astfel, dac mulimea de elemente E1, E2, , En are exact n elemente:
1 < poz (Ej) < n
poz (succ (Ej)) = poz (Ej) + 1
poz (pred (Ej)) = poz (Ej) - 1
Din cele dou relaii rezult c:
poz (succ (Ej)) - poz (pred (Ej)) = 2
sau:
( )
( ) ( ) ( ) ( )
2
Ej pred poz Ej succ poz
Ej poz
+

Cu aceste definiii:
adr(Ej) = A + (poz(Ej) 1) *lg(Ej)
Se construiete irul de perechi:
(cont(Ej.x), poz(Ej))
care permite, n cazul n care se stabilete o relaie de forma:
poz(Ej) = (cont (Ej.x))
regsirea elementului dup poziie pe care o are n fiier.
n cazul n care nu se identific funcia ( ), elementele (cont (Ej.x), j = 1, 2, ..., n, vor fi memorate ntr-o structur
omogen unidimensional i poziia elementului n care este memorat aceast informaie, corespunde poziiei articolului n fiier.
10.6. Alegerea tipului de fiier
Diversitatea de fiiere face ca, statistic, utilizarea unora s fie n anumite cazuri mai eficiente dect a altora. Experiena
fiecrui programator este cea care hotrte tipul de fiier cu care se lucreaz pentru fiecare aplicaie.
La alegerea tipului de fiier cu care se lucreaz, concur o serie de factori din care se enumer:
- numrul de elemente care alctuiesc fiierul;
- tipul prelucrrilor: integrale, dup o cheie, prin selecie;
- frecvena i tipul operaiilor de actualizare;
- durata impus de prelucrare i necesitatea sortrii datelor;
- timpul disponibil pentru elaborarea programelor;
- costuri de elaborare i utilizare;
- sistemul de calcul disponibil;
- sistemele de gestiune a fiierelor cunoscute i disponibile;.
Alegerea tipului de fiier i comportamentul algoritmilor implementai pentru regsirea informaiilor, sunt rezultatul unei
analize statistice a datelor, nregistrate prin urmrirea n timp a comportamentului la prelucrare.
PRODUSE PPProdusul x PP
MATERIALE
Cod mat.1 ..
Cod mat. 2 ..
Cod mat. 3. ..
Cod mat. 4 .. CC
PRODUSE PP
y111
y2 yy
y3 yy
y4 yy
MATERIALE MM
y111 x111
x2 xx
x3 xx
x4 xx
10.7. Fiiere interdependente
Interdependena fiierelor, este privit sub dou aspecte i anume: interdependena la nivelul articolelor unui fiier i,
respectiv, interdependena la nivelul a dou sau mai multe fiiere.
Se consider dou fiiere:
- fiierul PRODUSE, ale crui elemente sunt generate dup structura PROD, cu cmpurile cod produs, denumire produs, stoc,
unitate de msur, numr materii prime care intr n componena sa i materiile prime, gama de operaii;
- fiierul MATERIALE, ale crui elemente sunt generate dup structura MAT, cu cmpurile cod material, denumire material,
unitate de msur, cantitate existent n stoc, pre unitar.
Dac dorim s aflm costul materiilor prime necesare realizrii unui produs, citim din fiierul PRODUSE, articolul
corespunztor respectivului produs i rnd pe rnd prelum codurile materialelor ce intr n componena sa. Pentru fiecare
material ce intr n componena produsului, citim cte un articol din fiierul MATERIALE.
S ne imaginm c fiierele sunt secveniale. Rezolvarea este extrem de greoaie, pentru ca accesul la materiale este
obinut numai prin baleierea de la nceput a fiierului MATERIALE, dac materialele nu au fost memorate n ordine cresctoare
dup codurile acestora n articolul din fiierul PRODUSE i dac fiierul MATERIALE nu este sortat.
Problema devine eficient dac, n locul codurilor materialelor, dispunem de adresele articolelor n fiierul
MATERIALE, dar reorganizarea fiierului de materiale, ar atrage dup sine actualizarea adreselor pentru materiale din
componena fiierului PRODUSE.
Dac se lucreaz cu fiiere indexat secveniale, rezultatul este bun, iar dac se folosesc poziiile materialelor dintr-o
list, performana devine i mai bun.
Acest tip de dependen este unidirecional ntre dou fiiere. Numrul de legturi dintre un articol din fiierul
PRODUSE i fiierul MATERIALE este variabil, strict dependent de numrul de materiale ce intr n componena produsului cu
care articolul din fiierul PRODUSE este pus n coresponden.
Cod
produs
Denumire
produs
UM Pre
.
Nr. mat.
4
Cod
mat. 1
Cod
mat. 2
Cod
mat. 3
Cod
mat. 4
Este de dorit ca fiierele PRODUSE i MATERIALE, s se realizeze ntr-o prim etap cu codurile materialelor i lng
ele s fie rezervate cmpuri pentru memorarea adreselor fizice ale articolelor ce corespund n fiierul MATERIALE, respectivelor
coduri.
n a doua faz, un sistem de programe identific poziia fiecrui articol i ncarc n fiierul PRODUSE n zonele
disponibile de adres, chiar adresa articolului al crui cod se afl n imediata sa vecintate.
Reorganizarea fiierelor pe fondul definirii codurilor, nu implic dect rencrcarea de adrese, lucru ce se efectueaz
automat.
Fiierele interdependente privesc legturi ntr-un singur sens, de la fiierul de produse ctre fiierul de materiale. Se
construiesc i legturi n sensul opus, pentru fiecare articol al fiierului de materiale, indicndu-se n care dintre produse, este
folosit respectivul material. Este o informaie necesar, dar care lungete mult articolul MAT i de aceea, n acest caz este puin
utilizat o astfel de abordare.
Dac totui se dorete i o legtur dinspre fiierul MATERIALE ctre fiierul PRODUSE, realizarea se efectueaz n
acelai fel, parcurgndu-se tot doi pai.
n final se vor obine legturile dintre articole, ilustrate n figura de mai jos:
PRODUSE PPProdusul x PP
MATERIALE
Cod mat.1 ..
Cod mat. 2 ..
Cod mat. 3. ..
Cod mat. 4 .. CC
PRODUSE PP
y111
y2 yy
y3 yy
y4 yy
MATERIALE MM
y111 x111
x2 xx
x3 xx
x4 xx
NULL | G
1
O
11
|
G
1
O
12 11
G
1
O
13 11
G
1
O
1k 11
NULL | G
n
O
n1
|
G
n
Ok
nnn
Gama de
operaii
G
111
Gama de
operaii
G
nnn
Rezult c produsul y3, utilizeaz materialele x1, x2 i x4, iar materialul x3 este prezent n compoziia produselor y1 i y2.
Articolele fiecrui fiier rmn n continuare independente unele de celelalte. Ele sunt prelucrate separat, singurele
combinaii fiind cele legate de posibilitatea de a permite calculul necesarului de materiale, pentru realizarea de k produse de tipul
y3 i de a stabili dac stocurile materialelor x1, x2, x4 sunt suficiente.
La serviciul aprovizionare, prin parcurgerea fiierului MATERIALE, se observ care sunt viitoarele cereri din materialul
x3.
Observm c o astfel de construcie este limitativ, dar cu o serie de artificii de consultare a celor dou fiiere, se mai
obin i alte regrupri de date.
O privire de ansamblu pune n eviden c rmnerea articolelor din fiecare fiier ca entiti independente, reduce
diversitatea combinaiilor (compunerilor) de date, care pentru un manager competent, reprezint o surs sigur de fundamentare a
deciziilor.
10.8. Fiiere nlnuite
Apar ntrebrile: structurile dinamice (necontigue) cu multe elemente, sunt memorate pe suport extern? Se
implementeaz mecanisme de nlnuire n memoria extern? Cum se genereaz legturile exprimate prin adrese dintre elementele
deja alocate dac se specific numai cheile de identificare a acestora?
Rspunsurile nu sunt simple, dar au fost date cu muli ani n urm, obinndu-se funcii de creare i prelucrare a fiierelor
nlnuite.
Se consider c pentru realizarea unui produs, este necesar parcurgerea unor etape, efectuarea unor operaii de
prelucrare ntr-o anumit succesiune, numit gama de operaii.
Descrierea unei operaii, conine informaii precum:
- codul operaiei;
- denumirea operaiei;
- durata de execuie;
- calificarea cerut;
- tipul de meseria care o execut;
- utilajul necesar;
- scule necesare;
- plata pentru efectuarea operaiei;
- operaia precedent;
- operaia urmtoare;
La execuia programului de ncrcare a fiierului gamei de operaii, se introduc rnd pe rnd, datele ce urmresc ablonul
descris mai sus. Pentru primul articol al unei game, operaia precedent este NULL, iar pentru ultimul articol din gam, operaia
urmtoare este de asemenea NULL.
Sistemul de creare a fiierului cu acest tip de nlnuire, adaug dou cmpuri ce vor fi iniializate cu adresele ce
corespund poziiei articolelor pentru operaia precedent i pentru operaia urmtoare din gama de operaii.
Cte game de operaii sunt definite ntr-un proces de producie, tot attea liste dublu nlnuite vor fi realizate.
PRODUSE PP
y111
y2 yy
y3 yy
y4 yy
MATERIALE MM
y111 x111
x2 xx
x3 xx
x4 xx
NULL | G
1
O
11
|
G
1
O
12 11
G
1
O
13 11
G
1
O
1k 11
NULL | G
n
O
n1
|
G
n
Ok
nnn
Gama de
operaii
G
111
Gama de
operaii
G
nnn
AAA
BBB CCC
DDD EEE
Prin parcurgerea unui fiier cu articole nlnuite, aflm care este necesarul de specializri i care sunt salariile ce trebuie
pltite, dac realizm K produse de tipul X, pentru care este necesar efectuarea operaiilor din gama de operaii cu un cod
specificat.
Fiierul gamei de operaii, va avea elemente (articole) ce corespund gamelor G1, G2, ..., Gn, care la rndul lor conin
operaiile O11, O12, ..., Ok1, ..., O21, O22, ..., Ok2, ..., On1, On2, ..., Okn.
O alt situaie, este aceea corespunztoare memorrii pe suport extern a structurilor arborescente.
Se consider c la o ntreprindere se realizeaz N produse P1, P2, ... PN. Fiecrui produs i se asociaz o structur
arborescent, deci vor exista N noduri rdcin i N noduri terminale.

N
i
Ki M
1
unde, Ki reprezint numrul de materii prime, repere sau subansamble nerealizate n ntreprindere i care intr n componena
produsului Pi.
Se pune problema memorrii celor N arborescente, cu condiia realizrii cel puin a unui nivel de redundan controlat,
dac minimizarea este dificil de realizat (i n unele cazuri chiar nu este dorit).
Nodurile reprezint produse, subansamble, repere sau materii prime, despre care trebuie cunoscut:
- codul de recunoatere (cheia);
- denumire;
- unitate de msur;
- cantitate necesar (greutate specific);
- preul unitar;
- gama de operaii;
- codul reetei de fabricaie;
- caracteristici de performan standard;
De asemenea, se impune stabilirea poziiei n arborescen, indicnd nodul printe, nodul descendent i nodul vecin din
dreapta.
Aceast multitudine de date, se grupeaz n dou categorii:
- date pentru descrierea componentei ce corespunde unui nod;
- date pentru descrierea poziiei nodului n arborescen.
Celor dou categorii de date, le vor corespunde fiiere descriptive i fiiere de legturi.
Fiierele descriptive, au articole formate din dou tipuri de date:
- date ce se completeaz de ctre utilizatori cu acele elemente ce caracterizeaz un produs, un ansamblu, subansamblu, reper sau
materie prim:
- date ce se completeaz de un sistem de gestiune a fiierelor nlnuite i care conin adrese de articole sau identificatori de
marcare a finalului nlnuirii.
De exemplu, pentru produsul A care este format prin asamblarea reperelor B, C, D i E, n ordinea menionat mai jos,
NULL | G
1
O
11
|
G
1
O
12 11
G
1
O
13 11
G
1
O
1k 11
NULL | G
n
O
n1
|
G
n
Ok
nnn
Gama de
operaii
G
111
Gama de
operaii
G
nnn
AAA
BBB CCC
DDD EEE
fiierul descriptiv, conine 3 articole ce corespund elementelor A, B, C, D i E, iar fiierul de structur, descrie legturile dintre
elementele A, B, C D, i E, conform arcelor ce definesc gradul de tip arbore.
Deci, acest fiier are articolele:
(A; B), (A; C), (C; D), (C; E)
Indicarea acestor articole, nu necesit o anumit ordine. Analiza perechilor este aceea care permite identificarea tuturor
elementelor necesare completrii cmpurilor de adres din fiierul descriptiv.
Astfel, ntr-o pereche (x;y) rezult c pentru nodul x, nodul y este descendent, iar pentru nodul y, nodul x este printe.
Nodul A, este printe pentru nodurile B i C, dar el nu apare n nici una dintre perechi ca descendent, deci A este nod
rdcin, iar n articolul din fiierul descriptiv ce corespunde produsului A, un cmp este completat cu NULL.
Nodul B, nu apare ca printe n nici o alt pereche, deci nu are descendeni. Se completeaz i un cmp din articolul
fiierului descriptiv ce corespunde reperului B.
Pentru regsirea rapid a informaiilor, nainte de a completa cmpurile din fiierul descriptiv, vor fi completate n
fiierul de legtur, cmpurile ce corespund adreselor fizice pe care le ocup articolele fiierului descriptiv.
Astfel, legturii corespunztoare perechii (A;B) i se asociaz n fiierul de legtur, articolul:
cod A cod B adr (articol A) adr (articol B)
Dac este analizat un produs, problema nu difer prea mult cu modul de reprezentare a structurilor dinamice n memoria
intern. Dac ns fiierul descriptiv, conine totalitatea nodurilor ce descriu cele N produse care se realizeaz, iar fiierul de
legturi, are attea elemente cte arce au cele N arborescene dup care se descompun produsele P1, P2, ..., Pn, avem o imagine mai
exact a ceea ce nseamn reprezentarea n memoria extern a datelor ce formeaz articole interdependente i care n final, dau
fiierele nlnuite.
Obinerea controlului asupra redundanei, revine la a deplasa informaii privind adresele din articolele fiierului
descriptiv, n fiierul de legtur. Dac se minimizeaz redundana, n sensul c fiierul de produse conine repere i materii prime
descrise o singur dat, reconstituirea arborescenei, se obine prin construirea tuturor adreselor de regsire, nu n articolele din
fiierul descriptiv, ci n articolele de legtur.
Problema traversrii unui arbore se menine din punct de vedere al semnificaiei, dar n cazul fiierelor nlnuite, revine
la a utiliza alternativ, informaii din fiierul de legturi i din fiierul descriptiv.
Operaiile care sunt specifice structurilor arborescente construire n memoria intern, sunt definite i n cazul
arborescenelor de pe mediile externe. Modificrile vizeaz pointeri, al cror coninut reflect adrese ale suportului extern.
Funciile specifice pentru lucru cu fiiere nlnuite, au ca parametri toate elementele necesare tergerii unui nod,
modificrii unor legturi sau a unor cmpuri. Adresele care apar la descrierea legturilor dintre noduri, permit parcurgerea
arborelui de la rdcin spre baz, sau de la orice nod ctre baz sau de la orice nod ctre rdcin.
Cnd se proiecteaz o anumit structur, nu numai list sau arbore, trebuie ca programatorul s se familiarizeze cu ideea ,
ca oricrui arc i corespund dou adrese. El trebuie s gseasc algoritmi pentru ncrcarea n cmpuri, pe care are obligaia s le
defineasc, a acestor dou adrese. Programatorul este obligat s cunoasc funciile care ntorc adresa fizic a nceputului zonal de
memorie pe care o ocup un anumit articol.
Dac sistemele de gestiune a fiierelor nlnuite, realizeaz aceste operaii pentru structuri arborescente sau pentru liste
(cazuri particulare de arborescene), n cazul structurilor oarecare, programatorul trebuie s-i construiasc funcii proprii. El are
grij s rezerve zone pentru adrese, i definete structura de date adecvat descrierii structurii produsului. De fiecare dat, va avea
grij ca ceea ce realizeaz, s nu genereze ambiguiti sau s conduc la reprezentri ce nu concord cu structura pe care dorete
s o implementeze n fiiere.
10.9. Fiierele bazei de date
AAA
BBB CCC
DDD EEE
persoana x pp
familie ff vecini vv
soie ss copii cc
vecinul
din fa dd
vecinul
din spate dd
vecinul
din st. dd
vecinul
din dr. dd
Copilul Y1 CC Copilul Y10 CC
Productor PP
Marca 1 MM Marca 2 MM
Model MM
Marca n MM
Culoare CC An fabric. AA
Din punctul de vedere al modului de structurare a datelor, bazele de date reprezint o form mai general de reprezentare
a datelor, care reflect caracteristici ale elementelor omogene ce definesc mai multe mulimi.
Fie mulimile M1, M2, ..., Mk, formate fiecare din n1, n2, ..., nk elemente, aa fel alese nct caracterizarea complet a unui
element xj (M1), este efectiv dac sunt prezentate datele dj1, dj2, ..., djk, unde djk (Mk).
n plus, fiecare mulime are elementele structurare dup o anumit regul. Punerea n coresponden a elementelor celor
k mulimi, conduc n numeroase situaii, ca unui element din mulimea Mi, s-i corespund mai multe elemente din mulimea Mj,
sau mai multor elemente din mulimea Mi, s le corespund un singur element din mulimea Mh.
Se observ c necesitatea de a separa informaiile n fiiere distincte, este dat n principal din dorina de a diminua
redundana dintr-un fiier, pe de o parte, i pentru a permite noi faciliti de exploatare a structurilor de date.
n continuare, se consider un exemplu clasic, foarte frecvent utilizat n descrierea principiilor i fundamentelor de
realizare a bazelor de date.
Fie mulimea M1 a persoanelor dintr-o localitate, care se afl ntr-una din relaiile:
x este vecin cu y
x este fiul lui y
x este tatl lui y
x este soia lui y
x este soul lui y
Un individ al colectivitii, este descris prin:
- nume;
- adresa;
- raport cu ali indivizi (vecini, rude);
- tipul de automobil/marca;
- culoare automobil,
- anul cumprrii;
- loc de munc.
Fie mulimea M2 mulimea automobilelor, n care elementele se afl n relaiile:
marca x este produs de y
marca x are capacitate z
capacitatea z are consumul specific w
Un autoturism este descris prin:
- nume productor;
- model;
- culoare;
- an fabricaie;
- capacitate;
- tip combustibil;
- caracteristici motor;
- consum la 100 km.
Fie M3 mulimea locurilor de munc, format din elemente caracterizate prin:
- nume instituie;
- capital social;
- tip instituie;
- numr salariai;
- nume compartiment;
- nume meserii acceptate la compartimentul respectiv;
- numele lucrtorilor din compartiment.
Fie M4 mulimea impozitelor care se aplic mijloacelor de transport, format din elementele:
- limita inferioar a capacitii cilindrice;
- limita superioar a capacitii cilindrice;
- impozit;
- taxa CASCO pentru primii 3 ani de funcionare;
- taxa CASCO pentru mainile cu vechime cuprins ntre 4 10 ani;
- taxa CASCO pentru mainile cu vechime mai mare de 10 ani.
Dei se discut foarte mult, cea mai costisitoare etap din activitatea de manipulare a bazelor de date o reprezint
ncrcarea acestora.
n cazul de fa, datele nu sufer o uzur moral rapid, pentru c vizeaz indivizii dintr-un cartier sau bloc. n cazul n
care fenomenul are o dinamic accelerat, observm c la terminarea ncrcrii, 60 80% din date sunt uzate moral i baza de
date practic este inoperant.
n cazul considerat, cele patru mulimi conduc la date ce alimenteaz baza de date i se trage concluzia c n continuare
ea este complet ncrcat.
Pentru a vedea puterea de prelucrare pe care software-ul bazei de date o are, exemplificm cteva cereri:
- listarea locurilor de munc ale membrilor familiei lui x;
- listarea proprietarilor de autoturisme cu culoarea z;
persoana x pp
familie ff vecini vv
soie ss copii cc
vecinul
din fa dd
vecinul
din spate dd
vecinul
din st. dd
vecinul
din dr. dd
Copilul Y1 CC Copilul Y10 CC
Productor PP
Marca 1 MM Marca 2 MM
Model MM
Marca n MM
Culoare CC An fabric. AA
- listarea tuturor celor care lucreaz la locul de munc w i au autoturisme pentru care pltesc taxa CASCO cuprins n intervalul
[a, b];
- exist o relaie ntre capitalul social al firmelor i uzura moral a autoturismelor pe care le au salariaii lor?
- listarea proprietarilor care pltesc un impozit mai mare dect C lei i taxa CASCO mai mare dect D lei;
- exist meseriai de tipul z care au maini de tipul u absolut noi i care au vecini n aceeai situaie?
Dac toate datele despre un individ, ar fi nregistrate ntr-o structur cuprinztoare, care ar conine elementele de
descriere ale celor patru mulimi, s-ar observa o multitudine de repetri, ceea ce ar conduce de fapt la regruparea informaiilor.
Cele 4 mulimi nu sunt un dat, ci sunt rezultatul unei analize a modului n care sunt sistematizate i concentrate datele.
Pentru elementele din mulimea M1 se asociaz arborescena:
Pentru elementele mulimii M2 se asociaz arborescena:
i pentru elementele mulimii M3 i M4 se asociaz de asemeni, arborescene.
Deci, dac fiecare mulime este concretizat n cte un fiier, articolele n cadrul fiecrui fiier sunt legate ntre ele,
funcie de structura arborescenei asociate.
Baza de date presupune att legturi ntre articolele fiecrui fiier, ct i legturi ntre fiiere.
Se ridic ntrebarea: pentru a rspunde la toate solicitrile, este necesar constituirea unor structuri de adrese; toate
structurile de adrese sunt create de la nceput sau acestea se creeaz pe msur ce necesitile de prelucrare impun acest lucru?
persoana x pp
familie ff vecini vv
soie ss copii cc
vecinul
din fa dd
vecinul
din spate dd
vecinul
din st. dd
vecinul
din dr. dd
Copilul Y1 CC Copilul Y10 CC
Productor PP
Marca 1 MM Marca 2 MM
Model MM
Marca n MM
Culoare CC An fabric. AA
n fiierul persoanelor, cmpul corespunztor autoturismului conine i adresa articolului ce corespunde mrcii i culorii
autoturismului.
Dac intereseaz listarea proprietarilor de maini de culoare z se, procedeaz astfel:
Se construiete irul:
S = (s1, s2 sn)
unde, si este adresa articolului pentru descrierea autoturismului al crui proprietar este persoana ai din fiierul de persoane.
Din fiierul autoturismelor se extrage subirul:
P = (p1, p2, pn)
al adreselor articolelor ce corespund autoturismelor de culoare z.
p

s = (sk1, sk2, skm)


ceea ce nseamn c persoanele ale cror nregistrri ocup poziiile k1, k2, km cu maini de culoare z i afiarea
cont (ref (ki) . nume)
i = 1, 2, , m, conduce la tabelarea numelor de persoane care posed maini de culoare z.
Interogarea unei baze de date, revine la constituirea mai multor iruri, din fiecare mulime cte unul. Numrul de iruri
maxim este de regul egal, cu numrul mulimilor de articole definite.
Astfel dac se dorete listarea tuturor celor care au locul de munc w i au autoturism pentru care pltesc o tax CASCO
cuprins n intervalul [a, b], se procedeaz astfel:
Se construiete irul adreselor persoanelor care au locul de munc w:
( j = const (w.adresa_persoanaj))
j = 1, 2, n
Se construiete irul capacitilor cilindrice:
(C1, C2, Ch)
al autoturismelor, nsoite de adresele articolelor din fiierul asociat mulimii M2, ce corespund autoturismelor pentru capacitile
identificate:
m1 m2 me
de regul, e >= h, ntruct exist mai multe mrci de maini cu aceeai capacitate cilindric.
Prin analiza coninutului fiierului M4, rezult c autoturismele pentru care se pltete o tax CASCO cuprins n
intervalul [a, b], sunt cele care au capacitile cuprinse ntre:
[1, 1]
[2, 2]
Aceste limite conduc la filtrarea elementelor mulimii (C1, C2, Ch) astfel nct, rezult submulimea adreselor:
m = {m1, m2, mp},
de regul p < e.
Se construiete irul de adrese:
u = (i 0 <= 1 < k; cont (.i.adresa_autoturism) m)
Scrierea elementelor irului:
(cont (u->nume_persoana)), u = 1, 2, , w
rezolv cererea formulat iniial.
n exemplul dat, s-a procedat la utilizarea de variabile pointer. Pentru a face deosebire ntre pointerii folosii la referirea
elementelor din memoria intern i pentru a evita confuziile ce apar folosind conceptul de pointer spre fiier (ntruct este deja
concentrat tipul de dat FILE). n continuare utilizm conceptul de pointer extern.
Fiind dat un suport extern al cror baii au adresa cuprins ntre valorile [A, B]

N, A < B i A, B N, variabila v se
spune c este pointer extern dac i numai dac:
cont (v) [A, B]

N
Poziionarea citirii, este de fapt atribuirea sau modificarea coninutului unei variabile de tip pointer extern, aa fel nct,
ea s conin adresa baitului de unde ncepe citirea/scrierea.
n enunul problemei, M1, M2, M3 i M4, reprezint fiiere, adic variabile pointer care sunt iniializate cu adresele baiilor
de unde ncepe alocarea memoriei externe pentru fiecare din cele patru fiiere. Dac se are n vedere c fiierul are i o etichet de
nceput de lungime , cont (Mi) + , reprezint adresa primului articol din fiierul Mi.
Presupunnd c fiierului Mi i se aloc o zon contigu, cuprins ntre adresele [Ai, Bi], rezult c:
cont (Mi) = Ai
cont ( i) = Bi lg (Si)
unde, i reprezint adresa ultimului element de structur Si al fiierului Mi care are o etichet de sfrit de fiier de lungime .
Revenind la fiierele interdependente, la fiierele nlnuite, observm c structurile de date ce se asociaz fiierelor, pe
lng informaiile utile date de programator, se definesc nc multe cmpuri de tip pointer extern, care asigur traversrile prin
structura extern pe timpul execuiei.
Folosind definirea pointerilor extern, locul de munc w, este identificat prin pointerul extern pw, ce corespunde adresei
articolului respectivului loc de munc.
Mulimea m1, m2, me, reprezint valori ale variabilei pointer extern r, asociat fiierului M2:
m = { rj cont (rj->capacitate) {C1, C2, Ch}}
i < j < nrr (M2)
unde, nrr ( ) este o funcie care definete numrul de articole existent ntr-un fiier.
nrr : {F1, F2, Fk} > N
unde, F este mulimea fiierelor, date prin valoarea iniial a pointerilor lor externi.
m = { mi cont (mj-> capacitate) [1, 1]

[2, 2] }
Selectarea elementelor reprezint construirea de iruri de adrese i apoi prin operaii de reuniune, intersecie, se obin irurile de
elemente care prezint rezolvarea problemei.
Utilizarea bazelor de date, reprezint un domeniu al informaiei aplicate. Construirea de sisteme de gestiune a bazelor de
date, reprezint o preocupare de mare importan pentru toi realizatorii de software, iar elementele prezentate acum, definesc doar
o serie de trsturi generale ale filozofiei bazelor de date.
Fiecrui mecanism particular i corespund reguli precise de definire, iniializare i modificare a pointerilor externi ce se
asociaz fiecrui articol.
De menionat, ca n spatele oricrei cereri de informaie furnizat de utilizatorul bazei de date, se afl pointeri externi,
care n unele cazuri sunt deja iniializai i se folosesc ca atare, iar n alte cazuri, sunt numai definii i i ncarc coninutul n
funcie de cerere.
Exist situaii cnd pentru a rezolva o problem, se definesc noi pointeri externi i se activeaz proceduri de iniializare,
n concordan cu problema de rezolvat. n acest caz se creeaz noi legturi ntre elemente, cu noi posibiliti de selectare a
informaiilor din baza de date.
11. OBIECTE I CLASE
11.1. Diversitatea datelor
n multe cazuri, se confund diversitatea datelor cu complexitatea datelor. Diversitatea datelor pune n eviden tipurile
de date care particip la construirea unei structuri: ponderea pe care fiecare dintre tipuri o are n structur, influeneaz indicatorul
de diversitate D, care are forma:


n
i
fi fi D
2
2
log
unde:
n numrul de tipuri distincte care intr n alctuirea structurii de date;
fi frecvena apariiilor tipului Ti.
Restricii asupra definirii obiectelor n limbajul C/C++.
Tipul de dat obiect, se definete numai la nceputul programului. Elementele ce sunt definite ntr-o dat de tip obiect,
sunt fiierele.
Obiectele nu se definesc n funcii, proceduri sau n programul principal. Observm c tipul de date obiect este global.
Astfel, prin structura stud definit prin:
struct stud
{
int marca;
char nume[20];
char prenume[20];
int varsta;
int media;
int an_studii;
char facultatea[50];
char sectia[40];
int grupa;
int bursa;
int nr_examene;
int nr_absente;
};
se identific numrul de tipuri n = 2 (sunt utilizate 8 date de tip integer i 4 date de tip string).
Indicatorul de diversitate:
D = 8 log2 8 + 4 log2 4 = 32
Complexitatea datelor ofer prin indicatorii utilizai, o imagine mai exact asupra dependenelor ce se creaz ntre prile
ce alctuiesc structurile de date. Dac se asociaz unei structuri, arce prin care se marcheaz modaliti de traversare, indicatorii
de complexitate preiau i aceste elemente n calcul. Astfel, indicatorii de complexitate au forme analitice n care se include:
- numrul tipurilor de date;
- numrul datelor din fiecare tip;
- numrul arcelor care leag datele.
De exemplu, un indicator de complexitate, simplu dar sugestiv este:
C = n log2 n + m log2 m
unde:
n numrul tipurilor distincte de date;
m numrul de arce.
De exemplu, pentru lista liniar simplu nlnuit:
struct lista
{
int valoare;
lista * p_urmtor;
};
n care cele 17 elemente conin dou tipuri de date, iar ntre elemente se afl cte un arc, complexitatea este:
C = 2 log22 + 16 log216 = 66
n programe, se vorbete de structuri de date cu aceeai diversitate/complexitate. Ori de cte ori se ntlnesc multe
structuri cu valori ale indicatorilor D i C asemntoare, se ncearc analizarea posibilitii de optimizare, n sensul eliminrii
structurilor de date ce pot fi nlocuite cu structuri de date deja existente.
Apare problema: fiecare limbaj n care sunt definite tipuri de date, accept structuri cu o anumit diversitate i
complexitate depirea unor nivele determinnd ineficiena programelor. Singura modalitate de a depi aceste situaii, const n
construirea de noi tipuri de date, altele dect tipurile derivate.
Noile tipuri de date trebuie s se bucure de proprieti precum:
- posibilitatea de a cuprinde pe lng tipurile de baz i alte tipuri ce se asimileaz datelor.
- capacitatea de a accepta definiri de reguli i raporturi, cu alte componente de acelai fel sau alte componente ale programelor.
n capitolul destinat pointerilor, s-a fcut afirmaia c pointerii sunt date. De asemenea, pointerii spre funcii sunt date.
Textele surs sunt date, precum i textele executabile ale programelor sunt date. Se vorbete de tipul de dat pointer spre funcie,
de tipul de dat program surs i de tipul de dat program executabil. Pe lng tipurile de date descrise anterior, au mai aprut i
aceste trei tipuri derivate.
Apare problema efecturii unui salt calitativ i anume acela al includerii unuia dintre aceste trei tipuri n structuri. Noul
tip de dat, poart numele de obiect i a determinat o revoluie n activitatea de programare.
Discipline ca Programarea Orientat pe Obiecte POD, Baza de Date Orientate pe Obiecte, Proiectarea Orientat pe
Obiecte, vin s pun n eviden influena necesar asupra concepiei noi de rezolvare a problemelor, prin utilizarea curent n
programe a acestui tip de dat.
Un alt exemplu
Manualele de programare, articolele din revistele de specialitate n care se ncarc prezentarea programrii orientate pe
obiecte, ncep i dezvolt acelai exemplu de grafic, cu un cerc. Sugestiv exemplu, dar prea este singurul!
n continuare, se definete o alt problem, care propune o abordare a rezolvrii prin definirea i folosirea de obiecte.
Se consider datele privind stocurile de materiale la nivelul zilelor dintr-o lun. Lunar se ntocmete o situaie ce conine
valoarea stocurilor i total valoric la nivelul lunii. Trimestrial, se ntocmete i un raport centralizator, care preia totalurile fiecrei
luni. Anual se ntocmete un centralizator care preia totalurile fiecrui trimestru.
Observm de exemplu, c n luna iunie se obine att raportul lunar, corespunztor lunii, ct i raportul trimestrial, care
preia totalurile lunilor aprilie, mai i iunie.
De asemenea, observm c n luna decembrie, pe lng rapoartele lunar i trimestrial, se preiau totalurile din trimestrele
1, 2, 3 i 4 i se obine valoarea anual a stocurilor de materiale.
Deci:
a) pentru raportul lunar, exist datele stocurilor zilnice i funcia care calculeaz totaluri la nivel de lun;
b) pentru sfritul de trimestru, se calculeaz raportul lunar (a) i se preiau date pentru totalul trimestrial;
c) pentru sfritul de an, se calculeaz raportul lunar (a), raportul trimestrial (b) i se preiau date pentru raportul anual
Pentru rezolvarea acestei probleme, trebuie s procedm astfel:
- se definete o matrice a[31][4]; coloana a[i, 0] reprezint valoarea stocurilor iniiale la toate materialele n ziua a i-a din lun;
coloana a[i, 1] reprezint valoarea intrrilor; coloana a[i, 2] reprezint valoarea ieirilor i coloana a[i, 3] conine dup efectuarea
calculelor, valoarea stocurilor finale ale materialelor n ziua a i-a.
- se definesc variabilele tlsi, tlin, tlsf, ce corespund totalurilor pentru cele 4 coloane ale matricei a[31][4];
- se construiete funcia pentru calculul celor 4 totaluri;
- se definesc matricea b[3][4] i datele ttsi, ttin, ttie, ttsf ce corespund, respectiv, totalurilor din cele trei luni i totalurilor la nivel
de trimestru; se construiete funcia care face nsumrile;
- se definesc matricea c[4][4] i variabilele tasi, tain, taie, tasf, pentru totalurile celor patru trimestre i respectiv, pentru totalurile
anuale; se construiete funcia care face nsumrile;
Se observ ideea, de a grupa datele lng funciile care le prelucreaz, aspect normal dac se are n vedere c nu toate
datele sunt operanzi n toate funciile.
Se contureaz ideea definirii a trei obiecte:
- obiectul numit situaie_lunar;
- obiectul numit situaie_trimestrial;
- obiectul numit situaie_an.
Programul care prelucreaz datele astfel organizate este:
//Program situatii_obiect
#include <iostream.h>
#include <malloc.h>
typedef int mat1[31][4];
typedef int mat2[3][4];
typedef int mat3[4][4];
class situatie_lunara
{
public:
int xlsi, xlin, xlie, xlsf;
mat1 x;
void citeste_date (int ij);
void calcul_lun (int ij);
};
class situatie_trimestru
{
public:
mat2 y;
int ytsi, ytin, ytie, ytsf;
void calcul_trim (int kr);
void initializare_trimestru (int kr);
};
class situatie_an
{
public:
mat3 z;
int zasi, zaie, zain, zasf;
void calcul_an (int k);
void initializare_an (int k);
};
situatie_lunara luna[12]; // variabile utilizate
situatie_trimestru trim[4];
situatie_an an;
int m1, m, i, j, k;
void situatie_lunara::citeste_date(int ij)
{
int ii, jj, n;
for (ii = 0;ii<31;ii++)
for (jj = 0;jj<4;jj++)
luna[ij].x[ii][jj] = 0 ;
cout<<"\n Numar zile: ";
cin>>n;
for (ii = 0;ii<n;ii++)
{
cout<<"\n Stoc initial : ";
cin>>luna[ij].x[ii][0];
cout<<"\n Intrari : ";
cin>>luna[ij].x[ii][1];
cout<<"\n Iesiri : ";
cin>>luna[ij].x[ii][2];
luna[ij].x[ii][3] = luna[ij].x[ii][0] + luna[ij].x[ii][1]
- luna[ij].x[ii][2];
}
};
void situatie_lunara::calcul_lun( int ij)
{
int ii;
luna[ij].xlsi = 0;
luna[ij].xlin = 0 ;
luna[ij].xlie = 0 ;
luna[ij].xlsf = 0 ;
for (ii = 0;ii<31;ii++)
{
luna[ij].xlsi = luna[ij].xlsi + luna[ij].x[ii][0] ;
luna[ij].xlin = luna[ij].xlin + luna[ij].x[ii][1] ;
luna[ij].xlie = luna[ij].xlie + luna[ij].x[ii][2] ;
luna[ij].xlsf = luna[ij].xlsf + luna[ij].x[ii][3] ;
}
};
void situatie_trimestru::calcul_trim(int kr)
{
int ii;
trim[kr].ytsi = 0 ;
trim[kr].ytie = 0 ;
trim[kr].ytin = 0 ;
trim[kr].ytsf = 0 ;
for(ii = 0;ii<3;ii++)
{
trim[kr].ytsi = trim[kr].ytsi + trim[kr].y[ii][0];
trim[kr].ytin = trim[kr].ytin + trim[kr].y[ii][1];
trim[kr].ytie = trim[kr].ytie + trim[kr].y[ii][2];
trim[kr].ytsf = trim[kr].ytsf + trim[kr].y[ii][3];
}
};
void situatie_trimestru::initializare_trimestru(int kr)
{
int ii, jj, ll, tt;
for(ii = 0;ii<3;ii++)
for(jj = 0;jj<4;jj++)
trim[kr].y[ii][jj] = 0;
for(ii = (kr)*3; ii<(kr+1)*3;ii++)
{
ll = ii - (kr)*3 ;
for(jj = 0;jj<31 ;jj++)
for(tt = 0;tt<4 ;tt++)
trim[kr].y[ll][tt] += luna[ii].x[jj][tt];
}
};
void situatie_an::initializare_an( int k)
{
int ii, jj;
for(ii = 0;ii<4;ii++)
for(jj = 0;jj<4;jj++)
an.z[ii][jj] = 0;
};
void situatie_an::calcul_an( int k)
{
int ii , kk , jj , tt;
an.zasi = 0;
an.zain = 0;
an.zaie = 0;
an.zasf = 0;
for(kk = 0;kk<4;kk++)
for(jj = 0;jj<3;jj++)
for(tt = 0;tt<4;tt++)
an.z[kk][tt] += trim[kk].y[jj][tt];
for(ii = 0;ii<m;ii++)
{
an.zasi += an.z[ii][0] ;
an.zain += an.z[ii][1] ;
an.zaie += an.z[ii][2] ;
an.zasf += an.z[ii][3] ;
}
};
main()
{
cout<<"\n Numar trimestre : ";
cin>>m;
m1 = m*3;
for(int i = 0; i<m1;i++)
{
luna[i].citeste_date(i) ;
luna[i].calcul_lun(i) ;
}
for( i = 0; i<m1;i++)
{
cout<<"\n Luna - "<<i<<". . . . stoc_in = "<<luna[i].xlsi<<"\
intrari = "<<luna[i].xlin<<" iesiri = "<<luna[i].xlie<<"\
stoc_final = "<<luna[i].xlsf ;
}
for( k = 0; k<m;k++)
{
trim[k].initializare_trimestru(k) ;
trim[k].calcul_trim(k);
j = k;
cout<<"\n trim - "<<j<<". . . stoc_in = "<<
trim[j].ytsi<<" intrari = "<<
trim[j].ytin<<" iesiri = "<<trim [j].ytie<<
" stoc final = "<<trim[k].ytsf;
}
an.initializare_an(j) ;
an.calcul_an(k) ;
cout<<"\n TOTAL anual.... stoc_in = "<<an.zasi<<" intrari = "<<
an.zain<<" iesiri = "<<an . zaie<<" stoc final = "<<
an.zasf;
cin>>m;
}
Obiectul situaie_lunar, este definitor pentru obiectul situaie_trimestru. Obiectul situaie_trimestru este definitor pentru
obiectul situaie_an.
Elementele obiectivului definitor, se regsesc n obiectul definit. n mod natural, pentru calculul totalurilor la nivel de
trimestru, sunt necesare datele lunilor, iar pentru calculul la nivelul ntregului an, sunt necesare datele trimestrelor.
n program, sunt definite proceduri care opereaz cu datele ncapsulate ca i ele, n fiecare obiect.
Dac pentru prelucrare, se construiesc funcii care returneaz pointeri spre diferite tipuri de structuri, prin modificri
adecvate se obine o variant a programului de mai sus.
//Program functii_obiect
#include <iostream.h>
#include <malloc.h>
typedef int mat1[31][4];
typedef int mat2[3][4];
struct str1
{
mat1 a;
};
struct xx1
{
int xlsi, xlin, xlie, xlsf;
};
struct yyt
{
int ytsi, ytin, ytie, ytsf;
mat2 c;
};
struct zza
{
int zasi, zain, zaie, zasf;
};
typedef mat1 * pmat1;
typedef xx1 * pxx1;
typedef str1 * pstr1;
typedef yyt * pyyt;
typedef zza * pzza;
class situatie_lunara
{
public:
str1 aa;
xx1 bb;
pstr1 citire_date(int si);
pxx1 calcul_lunar(pstr1 );
};
class situatie_trimestru
{
public:
yyt c;
pyyt calcul_trim(pstr1);
};
class situatie_an
{
public:
zza dd;
pzza calcul_an (pyyt py);
};
situatie_lunara luna[12];
pstr1 ppstr[12];
pxx1 ppxx1[12];
situatie_trimestru trim[4];
int m1, n, m, i, j;
situatie_an an;
pyyt ppyyt[4];
pzza ppzz;
pyyt pyt1;
pstr1 situatie_lunara::citire_date(int si)
{
pstr1 ps;
int ii, jj, nn;
for (ii = 0;ii<31;ii++)
{
for (jj = 0;jj<4;jj++)
luna[si].aa.a[ii][jj] = 0 ;
}
cout<<"\n Numar zile: ";
cin>>nn;
ps = &luna[si].aa;
for (ii = 0;ii<nn;ii++)
{
cout<<"\n Stoc initial ";
cin>>luna[si].aa.a[ii][0];
cout<<"\n Intrari ";
cin>>luna[si].aa.a[ii][1];
cout<<"\n Iesiri ";
cin>>luna[si].aa.a[ii][2];
luna[si].aa.a[ii][3] = luna[si].aa.a[ii][0] + luna[si].aa.a[ii][1]
- luna[si].aa.a[ii][2];
}
return ps;
};
pxx1 situatie_lunara::calcul_lunar(pstr1 ps)
{
pxx1 px;
int ii;
px->xlsi = 0 ;
px->xlin = 0 ;
px->xlie = 0 ;
px->xlsf = 0 ;
for (ii = 0;ii<31;ii++)
{
px->xlsi += ps->a[ii][0] ;
px->xlin += ps->a[ii][1] ;
px->xlie += ps->a[ii][2] ;
px->xlsf += ps->a[ii][3] ;
}
return px;
};
pyyt situatie_trimestru::calcul_trim(pstr1 pp)
{
pyyt py;
int ii, jj, ix, jy;
py = &(trim[ i/4 + 1]);
if ((i%3) ==1)
for (ii = 0;ii<3;ii++)
for (jj = 0;jj<4;jj++)
py->c[ii][jj] = 0;
for (ii = 0;ii<m;ii++)
{
ix = (ii - 1) / 3 + 1;
jy = ii - (ix - 1) * 3;
for (jj = 0;jj<4;jj++)
py->c[ix][jj] += pp->a[ii][jj];
}
return py;
};
pzza situatie_an::calcul_an(pyyt py)
{
pzza pa;
int ii , jj;
// pa = &an;
pa->zasi = 0;
pa->zain = 0;
pa->zaie = 0;
pa->zasf = 0;
for(jj = 0;jj<m;jj++)
{
//py = &trim[jj];
for(ii = 0;ii<3;ii++)
{
pa->zasi += py->c[ii][0];
pa->zain += py->c[ii][1];
pa->zaie += py->c[ii][2];
pa->zasf += py->c[ii][3];
}
}
return pa;
};
main()
{
cout<<"\n Numar trimestre : ";
cin>>m;
m1 = m*3;
for(i = 0; i<m*3;i++)
{
ppstr[i] = luna[i].citire_date(i);
ppxx1[i] = luna[i].calcul_lunar(ppstr[1]);
}
for( i = 0; i<3*m;i++)
{
cout<<"\n Luna - "<<i<<" stoc initial = "<<ppxx1[i]->xlsi<<"\
intrari = "<<ppxx1[i]->xlin<<" iesiri = "<<ppxx1[i]->xlie<<"\
stoc_final = "<<ppxx1[i]->xlsf ;
ppyyt[(i/4)+1] = trim[(i/4)+1].calcul_trim(ppstr[i]);
}
for(i = 0; i<m;i++)
for(j = 0; j<3;j++)
{
cout<<"\n trim - "<<j<<" stoc initial = "<<
ppyyt[i]->c[j][0]<<" "<<
ppyyt[i]->c[j][1]<<" "<<ppyyt[i]->c[j][2]<<" "<<
ppyyt[i]->c[j][3];
}
ppzz = an.calcul_an(pyt1);
cout<<"\n TOTAL :"<<ppzz->zasi<<" "<<ppzz->zain<<" "<<ppzz->zaie<<
"stoc final = "<<ppzz->zasf;
}
11.2. Pointeri spre obiecte
Ca i n cazul celorlalte tipuri de variabile, tipului de dat obiect i se aloc dinamic memorie. Pentru aceasta trebuie:
- definit obiectul n partea de program TYPE ;
- definit un pointer spre tipul obiect definit anterior ;
- definita variabil pointer n parte de program VAR ;
- alocat memorie cu funcia NEW () i iniializat variabila pointer ;
- utilizarea membrilor obiectului folosind operatori de referire.
i n cazul definirii obiectelor, este posibil referirea pe mai multe nivele i evaluarea expresiilor de referire
folosind regulile deja cunoscute.
n exemplul anterior, la definirea obiectului s-a folosit o dat de tip adecvat. Apare firesc ntrebarea : este posibil
utilizarea unui pointer spre acel tip de dat i alocarea dinamic a memoriei? Rspunsul este afirmativ.
Pentru efectuarea alocrii dinamice a memoriei pentru o component opernd dintr-un obiect, care la rndul su este
alocat dinamic, se folosete funcia implicit numit CONSTRUCTOR () , iar pentru efectuarea dealocrii se folosete
funcia, de asemenea implicit, DESTRUCTOR ().
Se consider tot aplicaia de calcul a stocurilor, cu folosirea de aceast dat a alocrii dinamice de memorie pentru
obiecte:
//Program situatii_obiect
#include <iostream.h>
#include <malloc.h>
typedef int mat1[31][4];
typedef int mat2[3][4];
typedef int mat3[4][4];
class situatie_lunara
{
public:
int xlsi, xlin, xlie, xlsf;
mat1 x;
void citeste_date (int ij);
void calcul_lun (int ij);
};
class situatie_trimestru
{
public:
mat2 y;
int ytsi, ytin, ytie, ytsf;
void calcul_trim (int kr);
void initializare_trimestru (int kr);
};
class situatie_an
{
public:
mat3 z;
int zasi, zaie, zain, zasf;
void calcul_an (int k);
void initializare_an (int k);
};
typedef situatie_lunara * p_luna;
situatie_lunara luna[12]; // variabile utilizate
situatie_trimestru trim[4];
situatie_an an;
int m1, m, i, j, k;
p_luna pp_luna[12];
void situatie_lunara::citeste_date(int ij)
{
int ii, jj, n;
for (ii = 0;ii<31;ii++)
for (jj = 0;jj<4;jj++)
pp_luna[ij]->x[ii][jj] = 0;
cout<<"\n Numar zile: ";
cin>>n;
for (ii = 0;ii<n;ii++)
{
cout<<"\n Stoc initial : ";
cin>>pp_luna[ij]->x[ii][0];
cout<<"\n Intrari : ";
cin>>pp_luna[ij]->x[ii][1];
cout<<"\n Iesiri : ";
cin>>pp_luna[ij]->x[ii][2];
pp_luna[ij]->x[ii][3] = pp_luna[ij]->x[ii][0] +
pp_luna[ij]->x[ii][1] - pp_luna[ij]->x[ii][2];
}
};
void situatie_lunara::calcul_lun( int ij)
{
int ii;
pp_luna[ij]->xlsi = 0;
pp_luna[ij]->xlin = 0 ;
pp_luna[ij]->xlie = 0 ;
pp_luna[ij]->xlsf = 0 ;
for (ii = 0;ii<31;ii++)
{
pp_luna[ij]->xlsi = pp_luna[ij]->xlsi + pp_luna[ij]->x[ii][0] ;
pp_luna[ij]->xlin = pp_luna[ij]->xlin + pp_luna[ij]->x[ii][1] ;
pp_luna[ij]->xlie = pp_luna[ij]->xlie + pp_luna[ij]->x[ii][2] ;
pp_luna[ij]->xlsf = pp_luna[ij]->xlsf + pp_luna[ij]->x[ii][3] ;
}
};
void situatie_trimestru::calcul_trim(int kr)
{
int ii;
trim[kr].ytsi = 0 ;
trim[kr].ytie = 0 ;
trim[kr].ytin = 0 ;
trim[kr].ytsf = 0 ;
for(ii = 0;ii<3;ii++)
{
trim[kr].ytsi = trim[kr].ytsi + trim[kr].y[ii][0];
trim[kr].ytin = trim[kr].ytin + trim[kr].y[ii][1];
trim[kr].ytie = trim[kr].ytie + trim[kr].y[ii][2];
trim[kr].ytsf = trim[kr].ytsf + trim[kr].y[ii][3];
}
};
void situatie_trimestru::initializare_trimestru(int kr)
{
int ii, jj, ll, tt;
for(ii = 0;ii<3;ii++)
for(jj = 0;jj<4;jj++)
trim[kr].y[ii][jj] = 0;
for(ii = (kr)*3; ii<(kr+1)*3;ii++)
{
ll = ii - (kr)*3 ;
for(jj = 0;jj<31 ;jj++)
for(tt = 0;tt<4 ;tt++)
trim[kr].y[ll][tt] += luna[ii].x[jj][tt];
}
};
void situatie_an::initializare_an( int k)
{
int ii, jj;
for(ii = 0;ii<4;ii++)
for(jj = 0;jj<4;jj++)
an.z[ii][jj] = 0;
};
void situatie_an::calcul_an( int k)
{
int ii , kk , jj , tt;
an.zasi = 0;
an.zain = 0;
an.zaie = 0;
an.zasf = 0;
for(kk = 0;kk<4;kk++)
for(jj = 0;jj<3;jj++)
for(tt = 0;tt<4;tt++)
an.z[kk][tt] += trim[kk].y[jj][tt];
for(ii = 0;ii<m;ii++)
{
an.zasi += an.z[ii][0] ;
an.zain += an.z[ii][1] ;
an.zaie += an.z[ii][2] ;
an.zasf += an.z[ii][3] ;
}
};
main()
{
cout<<"\n Numar trimestre : ";
cin>>m;
m1 = m*3;
for(int i = 0; i<m1;i++)
{
pp_luna[i] = new (situatie_lunara);
pp_luna[i]->citeste_date(i) ;
pp_luna[i]->calcul_lun(i) ;
}
for( i = 0; i<m1;i++)
{
cout<<"\n Luna - "<<i<<". . . . stoc_in = "<<pp_luna[i]->xlsi<<"\
intrari = "<<pp_luna[i]->xlin<<" iesiri = "<<pp_luna[i]->xlie<<"\
stoc_final = "<<pp_luna[i]->xlsf ;
}
for( k = 0; k<m;k++)
{
trim[k].initializare_trimestru(k) ;
trim[k].calcul_trim(k);
j = k;
cout<<"\n trim - "<<j<<". . . stoc_in = "<<
trim[j].ytsi<<" intrari = "<<
trim[j].ytin<<" iesiri = "<<trim [j].ytie<<
" stoc final = "<<trim[k].ytsf;
}
an.initializare_an(j) ;
an.calcul_an(k) ;
cout<<"\n TOTAL anual.... stoc_in = "<<an.zasi<<" intrari = "<<
an.zain<<" iesiri = "<<an . zaie<<" stoc final = "<<
an.zasf;
cin>>m;
}

11.3 Funcii virtuale
Pn acum s-a vzut c variabilele de tip obiect reprezint zone de memorie cu o structur ce include i pointeri spre
funcii. Dup aceea s-a pus n eviden modul de referire a variabilelor de tip static a membrilor acestora operanzi sau funcii.
S-au definit pointeri spre obiecte i s-a efectuat alocare dinamic, ca pentru o variabil de tip STRUCT. S-au definit
funcii de tip CONSTRUCTOR () i DESTRUCTOR (), ce ofer posibilitatea de a aloca /elibera dinamic memorie, pentru a
iniializa pointeri definii ca membri n structura de date de tip obiect. Zonele de memorie alocate corespund unor operanzi.
n capitolul destinat pointerilor, se specific existena pointerilor spre funcie, care prin iniializri adecvate
determin succesiuni de prelucrri extrem de mobile i de complexe.
Cum n structura de date de tip obiect, sunt definite funcii i proceduri, apare n mod firesc ntrebarea dac se
definesc pointeri spre acestea, dac aceti pointeri sunt iniializai n timpul execuiei.
Rspunsul este afirmativ i rezolvarea este dat cu ajutorul funciilor virtuale, cam pretenios numite astfel.
Funciile de tip constructor sunt n continuare de tip static, progrmatorul putnd defini n cadrul structurilor obiect
proceduri, funcii i funcii de tip destructor de un nou tip, numit VIRTUAL.
Funciilor virtuale, li se conserv informaii privind poziia pe care o ocup (adresa primei instruciuni executabile),
ntr-o structur de tip masiv unidimensional, atasat obiectului.
Dac n timpul execuiei, se dorete activarea unei funcii virtuale sau a alteia, se atribuie coninutul ce corespunde
respectivei funcii din masivul unidimesional, unei variabile de tip pointer spre obiect i prezena acestuia ntr-o secven
executabil determin prelucrarea.
Fie obiectele O1, O2, . . . Ok, i masivele unidimensionale A1, A2, . . . Ak, avnd n1, n2, . . . nk componente, funcie
de elementele ce alctuiesc structura obiectelor crora le corespund.
Presupunnd c fiecare obiect Oi, dispune de definirea unor funcii s-au proceduri virtuale, pij, j = 1, 2, , mk, cu
mk < nk, initializarea vectorului Ai se efectueaz:
cont Ai [ni mi + j] = adr (pij)
Dac se definesc variabilele v1, v2, ..., vk pointeri, respectiv spre obiectele O1, O2, . . . , Ok, atribuiri de forma:
vi = cont (Ai [h]), h [ni mi + 1 , ni]
secvenele:
v1
v2
....
vn
corespund lansrii n execuie a unor funcii.
Mai mult, datorit faptului c aceast categorie de pointeri spre obiecte corespunde unui tip mai general, regulile de
conversie de tip sunt la fel de riguros definite.
Variabilele de tip pointer spre obiect, sunt iniializate cu adresele membrilor - operanzi sau funcii. Pointerii spre
funcii, alctuiesc o mulime omogen, fapt care permite efectuarea de atribuiri oarecare.
De exemplu, variabila vi este definit ca pointer spre obiectul Oi, iar componenta Ak [r] conine adresa unei
proceduri virtuale Pkr, definite n obiectul Ok.
Atribuirea:
vi = cont (Ak [r]) ;
este corect, mai mult, nu necesit conversii.
n unele situaii, pentru a menine aceast cerin de necesitate a conversiilor, se impune ca funciile virtuale cu care se
atribuie aceeai variabil pointer, s fie de acelai tip, adic s ntoarc acelai rezultat, tiut fiind faptul c tipul de data program
executabil funcie, este marcat prin ceea ce el returneaz.
n concluzie, observm c modul de lucru cu obiecte, realizeaz deziderate mai vechi ale programatorilor:
- ncapsularea ntr-un obiect a operanzilor i operatorilor (funcii, proceduri);
- motenirea posibilitatea de a prelucra ntr-un anumit obiect care se definete, operatori i operanzi ai obiectelor
definite anterior;
- polimorfismul prin care un nume de funcie se redefinete ntr-o ierarhie de obiecte i se folosete conform
algoritmilor de prelucrare.
Se observ c, variabilele pointer permit lucrul cu toate tipurilor de date, putndu-se realiza construcii fie complexe, fie
bizare, iar singura condiie de apreciere, este c una dintre caracteristicile textului surs elaborat, s se amelioreze.
Deci, n versiunile ulterioare ale limbajelor, implementarea lucrului cu obiecte este vzut ca extensie, etapele urmtoare
punnd n eviden faptul c toate tehnicile de programare se ndreapt spre utilizarea obiectelor.
12. Compactarea datelor
12.1. Parametrii stocrii datelor
Volumul datelor este dat n mai multe feluri. Pentru o colectivitate ale crei indivizi se descriu cu acelai ablon,
volumul informaiilor este prezent prin numrul indivizilor. Avem o imagine suficient de clar, despre un fiier care conine
informaii referitoare la 30.000 persoane sau despre o matrice are 50 linii i 80 coloane, din punct de vedere al volumului de
date.
Pentru o mai bun precizare, se vor lua n considerare:
N numrul de indivizi ai colectivitii;
L lungimea structurii de date asociate unui individ;
B factorul de blocare;
R lungimea informaiilor reziduale;
Volumul de date V este dat de relaia:
V = f (N*L, B) + g(R)
unde, f i g sunt forme analitice ale dependenei dintre factorii considerai, forme ce se determin pentru tipuri de suport
extern de date, n mod corespunztor.
Volumul de date astfel calculat, este exprimat n numr de baii. Documentaiile tehnice consemneaz capacitatea
de memorare pentru fiecare tip de suport extern, ca numr maxim de baii.
Fie suportul extern i, avnd capacitatea Ci. Raportul:
100
Ci
V
pi
reprezint ponderea pe care o au datele memorate n volumul V, fa de capacitatea suportului.
De exemplu, pentru un suport de 1200 ko capacitate, un fiier care ocup 400 ko, ocup 33% din suport.
Dac un programator trebuie s stocheze informaii pe un suport de capacitate Ci, sub forma unor volume V1, V2, . .
. , Vn, el stocheaz numai k volume, ntruct:

<
k
1 j
Ci Vj
Apare ns problema existenei unei diferene, care descrie funcia obiectiv:

k
1 j
Vj Ci [min]
a unui model de optimizare a combinaiei de volume, care s conduc la acest obiectiv.
De exemplu, se consider:
Ci = 1000, V1 = 200, V2 = 500, V3 = 400, V4 = 300
Se calculeaz sumele:
S1 = V1 + V2 + V3 + V4 = 1400 > Ci
S2 = 200 + 500 + 400 = 1100 > Ci
S3 = 200 + 500 + 300 = 1000 = Ci *
S4 = 500 + 400 = 900 < Ci
S5 = 500 + 400 + 300 = 1200 > Ci
S6 = 200 + 500 = 700 < Ci
S7 = 500 + 300 = 800 < Ci
S8 = 200 + 300 = 500 < Ci
S9 = 200 + 400 = 600 < Ci
S10 = 400 + 300 = 700 < Ci
Din toate combinaiile, S3 reprezint varianta care conduce la o bun umplere a capacitii cu date.
Apar deci ca parametri de descriere ai utilizrii unui suport, urmtorii:
- gradul de ocupare;
- numrul de fiiere ;
- volumul de informaii stocat n fiier exprimat prin intermediul numrului de indivizi pentru care se face stocarea
sau numrul de cuvinte, depinznd de unitile de msur, de natura fiierelor.
Problema maximizrii, apare pentru:
- creterea gradului de umplere;
- creterea numrului de fiiere ce se stocheaz;
- creterea volumului de informaii.
Exist modaliti specifice, care vin s amelioreze unul sau altul dintre parametrii considerai, ceea ce influeneaz ns
asupra tuturor parametrilor, este compactarea datelor.
Prin compactarea datelor, nelegem totalitatea metodelor care conduc la reducerea lungimii exprimate n baii, a
datelor. Fiind dat o mulime de cuvinte:
A = {a1, a2, . . an}, de lungime l1, l2 , . . . ln,
compactarea datelor revine la a gsi funciile:
f : A K i g : K A
unde:
k = { k1, k2, . . . , km}
este mulimea cuvintelor compactate, aa fel nct exist o pereche (i, j), pentru care:
kj = f (ai)
ai = g (kj)
Funcia f () se numete funcie de compactare, iar funcia g () este funcia de decompactare.
Deci, orice metod de compactare este complet definit, dac s-a identificat i modalitatea de a reduce setul de date n
forma iniial, prin decompactare.
Pentru perechea (i , j):
lg( kj) < lg (ai)
Rezult c efectul compactrii, pentru un text format din cuvintele:
a1 a2 a3 a3 a3 a3
de lungime iniial:
L1 = 1g(a1 a2 a3 a3 a3 a3 a3) = 1g (a1) + 1g (a2) + 4*1g (a3),
Prin compactare este transformat n textul:
k1 k2 k3 k3 k3 k3
de lungime:
L2 = 1g (k1) + 1g (k2) + 4*1g (k3),
Cu indicile de eficien a compactrii:
100
L1
L2 - L1
p
12.2 Compactarea la nivel de caracter
Sistemel de coduri asociate caracterelor pornesc de la urmtoarele aspecte:
- mulimea caracterelor ce sunt reprezentate este finit; de exemplu, codul ASCII permite reprezentarea unei mulimi
de caractere formate din 256 elemente;
- lungimea exprimat n bii a unui element al mulimii, este constant; codul ASCII asociat unui caracter are 8 bii.
Pentru un ir de n bii, se asociaz o mulime format din2**n elemente distincte, ce sunt puse n coresponden cu simboluri
sau cuvinte, ale unei mulimi cunoscute.
Vom considera un roman, n care apar numai litere mici i litere mari, semne de punctuaie, separatorul blanc i
liniua corespunztoare semnului de dialog.
Analiza textului ce formeaz romanul, pune n eviden urmtoarele aspecte:
- dintre literele mari sunt utilizate 15;
- dintre literele mici sunt utilizate 24;
- semnele de punctuaie cu liniua de dialog, sunt n numr de 8.
Alfabetul nou cu care operm, este format din 24+15+8=47 simboluri. Fiecare simbol are reprezentare pe 6 bii,
ntruct cel mai mic numr natural pentru care 2**n > 47 este n=6.
Se vor pune n coresponden cele 47 de caractere, cu coduri de cte 6 bii i textul romanului care avea o lungime
iniial Li:
Li = 8 * m
unde, m reprezint numrul de caractere al textului.
Dup compactarea la nivel de caracter, textul compactat are o lungime final Lf:
Lf = 6 * m
Indicele de eficien al acestei compactri este:
% * 25 100
Lf
Lf - Li
p
Decompactarea, presupune interpretarea succesiunilor de 6 bii i nlocuirea lor, cu caractere ASCII corespunztoare din
stiva caracterelor utilizate n text.
12.3. Compactarea la nivel de cuvnt
Prin analiza textului, nelegem construirea unei stive a cuvintelor diferite din text i nregistrarea frecvenei lor de
apariie.
Dac meninnd codul ASCII pentru caracterele uzuale ale textului, punem n coresponden cuvintele avnd
frecvenele cele mai mari C1 C2 . . .Ck, cu coduri asociate unor caractere ce nu apar n text, indicile de eficien al
compactrii este:
100
Li
j f 1g(cj) * fi - Li
p
k
1 j
k
1 j
*


+

Dac stiva cu cuvintele definite C1 C2 . . . Ck, avnd frecvene ridicate f1 f2 . . . fk, este suficient de mare, i
mulimea { G } a simbolurilor neutilizate n text, este insuficient, este necesar construirea cuvintelor g1 g2 . . . gk
formate din 1, 2, . . . ng simboluri neutilizate, atunci performana compactrii este:
100
Li
1gj)] [1g(Cj) * fj - Li
p
k
1 j
*

Decompactarea revine la a nlocui cuvintele gj din text, cu cuvintele cj, ntruct att algoritmul de compactare ct i
cel de decompactare presupun existena stivei cuvintelor diferite ale textului iniial i cuvintele din mulimea {g1, g2, . . .
gk}, a cuvintelor formate din simboluri neutilizate n text.
12.4 Compactarea prin analiza caracteristicilor textului
Vom exemplifica modul de analiz al unui text, folosind reprezentarea n memorie a tabelului de mai jos ce trebuie
imprimat:
SITUAIA MATERIALELOR
5 30 15
NR.
CRT.
DENUMIRE VALOARE
0 1 3
1 CUIE 100
2 TABLA 200
3 VAR 600
TOTAL 900
Pentru memorarea acestui tabel, se definete un articol de 74 baiti i n fiierul TABEL.DAT, vor fi memorate 20
de rnduri, incluznd i blancurile dintre antet i capul de tabel. n fiierul TABEL.DAT vor fi ocupai 20*74=1480 baiti cu
acest tabel.
Prin convenie, ntruct asteriscul nu este utilizat, n continuare este folosit ca separator, iar dou asteriscuri
consecutive au semnificaia de CR.
27 30b*SITUATIA MATERIALELOR
23 30b*22 - **74b**10b*
27 54 = **10b*!*5b!*30b*!*15b**
60 10b*! NR. ! DENUMIRE ! VALOARE !**
25 10b*! CRT !*30b*!*15b*!**
22 10b*!*5b*!*30b*!*15b**
69 10b*54 = **10b*! 0 ! 1 ! 2 !**
69 10b*54 = **10b*! 1 ! CUIE ! 100 !**
60 10b*! 2 ! TABLA ! 200 !**
60 10b*! 3 ! VAR ! 600 !**
9 10b*54 = **
65 10b*! TOTAL ! 900 !**
7 10b*54 =
----
523 baii
Textul astfel codificat are lungimea de 523 baii.
Indicele de performan n acest caz este:
64% 100 *
1480
523 1480
p

Compactarea merge mai n profunzime, prin identificarea elementelor invariante. Apar n mod repetat
10b*54 = **
10b*!*5b*!*30b*!*15b*!**
Dac aceste succesiuni vor fi nlocuite, prima cu caracterul ' & ' iar a doua cu ' @ '.
68% 100 *
1480
21) 8 * 4 (523 1480
p'

Dac se pune n coresponden construcia **10b* cu ' : ', care are 10 apariii, nc se obine o ameliorare a
indicelui de eficien.
12.5 Compactare prin asocierea unor coduri ce permit eliminarea separatorilor
n textele de orice tip ar fi ele, se utilizeaz diveri separatori, care ocup un numr de poziii, depinznd de
regulile acceptate de utilizare, dintre care se enumer:
- separatorii punct i virgul sunt urmai de un spaiu;
- separatorul linie de dialog cnd este urmat de o liter mare sau precedat de punct sau dou puncte, este precedat de
3-6 spaii pentru a marca un dialog;
- cuvintele sunt separate prin cel puin un spaiu; n procesarea de texte, variabilitatea numrului de spaii depinde de
limea textului i de dorina de a realiza o aliniere la extremitile definite pentru un rnd.
Se consider de exemplu, nregistrarea profesiilor persoanelor ce alctuiesc o colectivitate. Din nregistrrile efectuate,
rezult mulimea de profesii distincte:
forjor
strungar
frezor
economist
mecanic
supraveghetor
Fiierul ce se creeaz, conine niruirea acestor profesii, urmnd ca programele pentru consultarea lui, s permit
numrarea elementelor ce aparin fiecrei meserii.
nregistrarea brut a informaiilor, conduce la ocuparea unei zone de memorie:
Lb = n1*1g(forjor) + n2*1g(strungar) +
+ n3*1g(frezor) + n4*1g(economist) +
+ n5*1g(mecanic) + n6*1g(supraveghetor)
Dac fiecare meserie este pus n corespondena cu un mnemonic precum:
fo pentru forjor
st pentru strungar
fr pentru frezor
ec pentru economist
me pentru mecanic
su pentru supraveghetor
n mod sever, lungimea ocupat se reduce.
n6) n5 n4 n3 n2 (n1 * 2 Lm + + + + +
Pentru eliminarea ambiguitii generate de reducerea lungimii mnemonicelor de la 2 caractere la un singur caracter, se
efectueaz punerea n coresponden a meseriilor cu caracterele:
f forjor
s strungar
r frezor
e economist
m mecanic
g supraveghetor
n aceste condiii, lungimea textului este:
n6 n5 n4 n3 n2 n1 Ls + + + + +
Forma brut a caracterelor, conduce la calculul lungimii fiierului n baii. Lungimea efectiv, exprimat n bii, este n
continuare redus dac meseriile sunt puse n coresponden cu iruri de bii, ce se bucur de o serie de proprieti suplimentare.
forjor 1
strungar 101
frezor 1001
economist 10001
mecanic 10101
supraveghetor 100001
Aceste construcii, se bucur de proprietatea ca prin concatenare, locul unde s-a produs aceast operaie apar dou cifre
binare 1. Astfel:
6 * n6 5 * n5 5 * n4 4 * n3 3 * n2 1 * n1 LB + + + + +
Observm c:
LB Ls * 8 Lb * 8 > >
n multe cazuri, lungimea cmpului este dimensionat n aa fel nct, s poat cuprinde meserii cu cele mai multe
caractere, fiierul avnd articole de lungime fix.
n exemplul dat, lungimea este dat de cuvntul supraveghetor, care are 13 caractere.
n6) n5 n4 n3 n2 (n1 * 13 * 8 LF + + + + +
Toi indicii de performan, se calculeaz n raport cu lungimea LF.
Dac de exemplu, ntr-o colectivitate de 1000 persoane:
n1=100, n2=300, n3=100, n4=100, n5=300, n6=100
LF = 8*13*1000 = 104000 bii
Lb = 100*6 + 300*8 + 100*6 + 100*9 + 300*7 + 100*13 =
= 600 + 2400 + 600 + 900 + 2100 + 1300 = 7900 baii
LB = 100 + 300*3 + 100*4 + 100*5 + 300*5 + 100*6 = 4000 bii
n cazul n care lungimea codurilor asociate, iau n considerare frecvenele aa fel nct, meseria cu cea mai mare
frecven s fie codul de lungime cel mai mic, se obine:
LB' = 300*1 + 300*3 + 100*4 + 100*5 + 100*5 + 100*6 = 3000 bii
97% 100 *
104000
3000 104000
p1

95% 100 *
8 * 7900
3000 8 * 7900
p2

25% 100 *
4000
3000 4000
p3

12.6 Compactarea prin identificarea de subiruri repetitive


Pentru cele 27 litere ale alfabetului, se construiete matricea frecvenelor de apariie a grupurilor de cte dou litere, X.
Astfel, xij reprezint numrul de apariii al literei cu poziia i, urmat de liter cu poziia j din alfabet.
Construirea matricei X se realizeaz, prin parcurgerea unei diversiti de texte i frecvenele depind de particularitile
fonetice ale fiecrei limbi.
Dintre grupurile de cte dou litere, vor fi extrase acelea cu frecvenele cele mai mari i vor fi dispuse pe linii ntr-un
tabel, ale crui coloane conin literele alfabetului.
Se construiete matricea Y, ale crei elemente yij, conin frecvenele de apariie ale grupului de dou litere de pe linia I,
urmat de litere de pe coloana j a tabelului.
Se are n vedere c totalitatea grupurilor de litere ce vor fi selectate n ordinea descresctoare a frecvenelor de apariie,
s nu depeasc un numr K aa fel nct:
K + L < 256
unde, L reprezint numrul de caractere considerat necesar pentru introducerea unui text ntr-un fiier.
n continuare, se vor considera cele 27 litere ale alfabetului, cele 10 simboluri ale cifrelor i caracterele: spaiu, plus,
minus, egal, punct, virgul, dou puncte, punct i virgul, semnul mirrii, semnul ntrebrii i asteriscul. n total sunt 48 de
caractere.
Din analizele statistice efectuate pe texte, se rein grupurile de litere alctuind o mulime format din 64 de elemente
dispuse n tabloul de mai jos, care au n dreptul liniilor i coloanelor combinaii de bii care alctuiesc codul asociat fiecrui ir.
1000 1001 1010 1011 1100 1101 1110 1111
1000 u1 1e pr mb mp ni in lui
1001 lor se ut re tr te ta nu
1010 it la ea ta ti ca oi au
1011 am ar ei ra ne un ns nt
1100 cr sc st os ti at ri oa
1101 sa ma ne tre ist tri urile ind
1110 nstr eau eam esti ndu u-se ati nul
1111 asera res tit ros oasa isem tit art

Aceste grupuri de litere au fost puse n coresponden cu codul unui caracter, altul dect cele 48 considerate.
Astfel, versurile eminesciene:
Dintre sute de catarge
Care leag malurile
Cte oare le vor sparge
Vnturile, valurile
A fost odat c-n poveti
A fost ca niciodat
Din rude mari mprteti
O prea frumoas fat.
care nsumeaz 177 caractere incluznd i spaiile care separ cuvintele, vor fi compacte astfel:
Dx x sux de x x rge
17 64 26 36 27
x x x aga x lux x
26 24 12 62 57 12
Cix x x x vor spx ge
26 58 24 12 42
Vix ux x , valux x
48 57 12 57 12
A fox odat c-an povex
53 73
A fox x x ciodat
53 26 16
Dx rude x x ix aratx
17 62 57 15 74
o x x fata
13 33 85
ceea ce conduce la un indice de performan:
22% 100 *
177
137 177
p

Construirea matricei generale a subirurilor, are avantajul c este unic pentru orice text care se compacteaz, dar poate
apare situaia ca frecvenele grupurilor n textul de compact, s nu urmeze nivelurile de frecven a textelor care au stat la baza
obinerii ei.
Dac pentru fiecare compactare, se construiete o matrice de subiruri proprie, performana este cu totul alta.
Pentru textul analizat, subirurile identificare se organizeaz ntr-un tabel, cruia i se ataeaz o matrice C a codurilor, ce
conduce la un text de 116 caractere, avnd un indice de performan:
34% 100 *
177
116 177
p

Dac pornim de la ideea c acest text este memorat folosind succesiuni de 6 bii, pentru c el conine 25 de combinaii de
bii, corespunztoare grupurilor de litere i cele 27 de litere, comparativ cu memorarea ca text avnd fiecare caractere cte 8 bii,
indicele de performan este:
52% 100 *
8 * 177
6 * 116 8 * 177
p

Observm c algoritmii de compactare, vizeaz att lungimea codului sub care se reprezint un caracter din text, ct i
modul n care se identific elementele invariante n texte.
Spaiul ocupat de textul compactat, i se adaug o zon cu informaii care permit reconstituirea textului iniial. Aceste
informaii conin:
- lungimea codurilor asociate caracterelor;
- mulimea subirurilor i a codurilor cu care acestea se pun n coresponden.
n cazul n care se identific pentru reguli complexe de scriere a textelor proceduri, acestea se pun n coresponden cu
coduri i ori de cte ori apar codurile respective n text, vor fi activate procedurile care vor prelucra textul adecvat.
De exemplu, dac un text este centrat pe un rnd, blancurile vor fi eliminate, respectivul text fiind precedat de un cod
care odat identificat, preia textul, l centreaz, reconstituind blancurile eliminate la compactare.
n cazul dialogurilor, nceperii unui nou paragraf sau scrierii unei formule, reconstituirea poziiei reale a textului, se
efectueaz cu ajutorul procedurilor activate odat cu apariia codurilor care semnalizeaz fiecare dintre situaiile menionate.
12.7 Compactarea programelor date n form executabil
Pentru utilizatori, prezint importan programele executabile. Obiectivele programelor care efectueaz compactarea
acestui tip de text, sunt gsirea unor modaliti care s determine stocarea unui numr ct mai mare de programe executabile pe un
suport. n acelai timp, se urmrete i gsirea posibilitii de a efectua decompactarea textului transformat.
Programele de compactare a programelor executabile, iau n considerare urmtoarele aspecte:
- limbajul de asamblare are o mulime finit de coduri de instruciuni, dintre care programatorii folosesc sub 40%, ca
diversitate n programe;
- programele executabile sunt rezultate ale compilrii i editrii de legturi; n cea mai mare parte, aceste operaii conduc
la o pondere ridicat a secvenelor construite mecanic, pe baza unor reguli tip;
- programele executabile, au ca entitate instruciunea i aceasta este plasat ntr-o zon de memorie de lungime i structur
fix; toate analizele, vizeaz componentele n numr restrns de pe o zon restrns; frecvenele construite vin s ajute
alturi de celelalte consideraii, la dimensionarea codurilor cu care se pun n coresponden, instruciunile programului
executabil.
Se consider n continuare programul:

ORG 420 H
MOV D , E
PUSH B
XRA A
CICLU: LDAX B
ADC M
DCR E
JZ BETA
STAX B
INX B
INX H
JMP CICLU
BETA: MOV
LOAX B
XRA M
MOV A , E
STAX B
STC
JM GAMA
MOV A , M
XRA E
STC
JM DELTA
GAMA: CMC
DELTA:POP B
MOV E , D
RET
END
Acestui program i corespunde codul obiect:
0420 53
0421 C5
0422 AF
0423 OA
0424 8E
0425 1D
0426 CA 2F 04
0429 02
042A 03
042B 23
042C C3 23 04
042F 5F
0430 OA
0431 AE
0432 7B
0433 02
0434 37
0435 FA 3F 04
0438 7E
0439 AB
0440 37
043B FA 3F 04
043F C1
0440 5A
0441 C9
0000
Textul obiect generat are 31 baii. Se vor scrie frecvenele de apariie a elementelor din acest text.
Element Frecvena
0
1
2
3
4
5
6
7
8
9
A
B
C
D
E
F
8
2
4
9
4 (04)
4
-
4
1
1
6
1
3
1
4
6
mprtierea cifrelor hexazecimale, reduce masiv posibilitatea efecturii unor prelucrri directe pe textul obiect.
Se procedeaz la efectuarea modificrilor:
a) se ncepe contorizarea de la zero i se memoreaz 0420 i textul devine:
0000 53
0001 C5
0002 AF
0003 OA
0004 8E
0005 1D
0006 CA 00 OF
0009 02
000A 03
000B 23
000C C3 00 03
000F 5F
0010 0A
0011 AE
0012 7B
0013 02
0014 37
0015 FA 00 1F
0018 7E
0019 AB
001A 37
001B FA 00 1F
001F C1
0020 5A
0021 C9
Cea mai mic valoare din prima cifr hexazecimal a prii de instruciune, este 0 i cea mai mare este F.
Element Frecvena
0
1
2
3
4
5
6
7
8
9
A
B
C
D
E
F
5
1
-
2
-
2
-
2
1
-
2
-
5
-
-
2
Din 15 simboluri lipsesc 7. Construim pe 2 baii masca elementelor absente:
0 1 2 3 4 5 6 7 8 9 A B C D E F
------------------------------------------------------------------------
1 1 0 1 0 1 0 1 1 0 1 0 1 0 0 1
Se analizeaz frecvena de apariie a cifrelor hexazecimale pe al II-lea bai al instruciunii:
Element Frecvena
0
1
2
3
4
5
6
7
8
9
A
B
C
D
E
F
-
1
2
4
-
1
-
2
-
1
6
2
-
1
3
2
Se construiete pe 2 baii masca elementelor absente:
0 1 2 3 4 5 6 7 8 9 A B C D E F
------------------------------------------------------------------------
0 1 1 1 0 1 0 1 0 1 1 1 0 1 1 1
Observm c pentru un text de lungime redus, elementele repetitive nu se identific i deci compactarea are efecte
reduse, uneori nule sau chiar pgubitoare.
Limbajele de asamblare moderne, au n definire operaii de tip RR (registru-registru) i ntruct numrul registrelor este
redus, sunt asociate coduri diferite pentru combinaia de cod operaie R1, R2 ceea ce reprezint o compactare la nivel de limbaj. Tot
astfel, n cazul instruciunilor memorate pe trei baii, deplasarea operandului este reprezentat pe un singur bai, prin recalcularea ei.
n cazul unor texte mult mai lungi, dac resursele sunt folosite convenabil i programatorii stabilesc reguli precise de
realizare a unor anumite prelucrri, compactarea este realizabil.
Astfel, n toate subprogramele, secvena de preluare a parametrilor este standardizat i deci este pus n coresponden cu
un cod i nlocuit cu acesta.
Aplicnd principiile de analiz ale textului, compactarea se realizeaz n principal prin tratarea elementelor repetitive i n
programele scrise n limbajul de asamblare sau generate de compilatoare, acestea nu au o pondere important.
12.8 Compactarea datelor numerice.
Reprezentarea matricelor rare, este un exemplu de compactare a datelor. n cazul seriilor de date, problema compactrii este
important dac seriile au variaii mici sau dac seriile au o lungime foarte mare.
Fie seria de date X avnd termenii:
11120 11130 11131 11136
11170 11135 11131 11109
11121 11122 11120 11104
Cei 12 termeni ai seriei de date, dac sunt reprezentai binar, ocup fiecare cte 2 baii, deci n total 24 baii. Observm c
termenul minim al seriei este 11104, iar termenul maxim este 11170.
0 = Xmax Xmin = 66
iar,
0,005
11108
60
Xmin
D

ceea ce arat c datele se afl ntr-un interval foarte ngust n raport cu mrimea lor.
Considerm Xmin = 11104. Se calculeaz o nou serie x'
xi' = xi xmin,
al crei termeni sunt:
16 26 27 32 66 51
27 5 17 18 16 0
Numerele acestea se reprezint pe 7 bii. Deci, pentru cei 12 termeni sunt necesari 84 de bii, iar pentru 11104 sunt necesari
2 bii.
52% 100
192
100
100
8 * 24
8 * 2 84
p
+

Compactarea la nivel de bii, se dovedete cu efecte mai importante dac se combin cu alte procedee de compactare.
111 111 111 112 112 112
113 113 111 112 112 112
Elementul minim este 111, iar elementul maxim este 113. n reprezentare binar a ntregilor, pentru fiecare termen este
necesar un bai. Seria aceasta necesit 12 baii.
Observm c exist elementele repetitive 111, 112 i 113, care vor fi puse n coresponden cu caracterele a, b, c, respectiv
00, 01, 10. Pentru cele trei numere sunt necesari 7 bii.
46% 100
96
45
100
8 12
2 12 7 3
p

12.9 Programe care efectueaz compactarea


Un program P de lungime L, se zice c este compactat de programul X, dac forma obinut P', are o lungime L' cu peste
20% mai mic dect lungimea L.
Programul X execut complet compactarea, dac ncercnd compactarea programului P', se obine un program P" de
lungime L" i dac L' = L" i P" este identic cu P'.
Programul Y realizeaz decompactarea programului P', dac dup executarea sa se obine programul P' ' ' de lungime L' ' ',
aa fel nct L' ' ' = L i P' ' ' este identic cu P'.
Programele de compactare sunt specializate s aib ca intrare, fie texte surs, fie texte obiect, fie componente executabile.
Exist i programe generale care efectueaz compactarea i decompactarea. Exemple de astfel de programe sunt PKZIP . EXE,
PKUNZIP . EXE, ARJ . EXE, PKARC . EXE. Fiecare dintre acestea folosesc algoritmi specifici de compactare, n funcie de tipul
fiierelor supuse comprimrii.
Formatul general al unei etichete de fiier arhivat, l descriem prin structura urmtoare n C:
struct fisier_compactat
{
int metoda_compactare[10];
20% 22
12% 11
10% 11
100 % 11
70 % 77
50 % 55
35 % 33
23% 22
13 % 11
5 % 55
000
000
000
000
000
000
000
111
111
111
111
111
111
111
1111111 11
000
10 11
110 11
1110 11
11110 11
111110 11
1111110 11
000
111
222
333
444
555
666
777
30% 33
15% 11
8% 88
5% 55
0% 00
000
100% 11
111111 11
000
110 11
100 11
101 11
1110 11
11110 11
000
111
222
30% 33
20% 22
15% 11
12% 11
10% 11
8% 88
5% 55
0% 00
333
444
555
666
777
000
000
111
70% 77
43% 44
111
000
111
111
000
000
111
111
23% 22
13% 11
5% 55
111110 11
000
111
27% 22
char nume_fisier[8];
char extensie_fisier[3];
unsigned char atribut_fisier;
short int data;
short int timp;
short int cluster_start;
long int lungime_fisier_initial;
long int lungime_fis_compactat;
int suma_control;
};
Se asociaz fiecrei metode de compactare folosit un anumit cod, ca de exemplu:
0 dac fiierul a fost memorat n forma sa iniial, compactarea nefiind
eficient;
1 dac fiierul a fost comprimat printr-un algoritm nerepetitiv;
2 dac fiierul a fost comprimat n mai multe etape.
Aceste probleme sunt nzestrate cu funcii specifice gestionrii de fiiere arhivate (adugare, tergere, modificare, protecie).
Unul dintre algoritmii utilizai de aceste programe de compactare este cel al lui Huffman. Acest algoritm are drept scop de a
minimiza numrul de bii necesar pentru reprezentarea oricrui simbol dintr-un alfabet. Astfel, se atribuie simbolurilor cu o frecven
de utilizare mare, coduri mai scurte, iar simbolurilor mai rar folosite, coduri mai lungi. n acest mod, media lungimii codului, este mai
redus.
Aceast tehnic a utilizat-o i Samuel Morse cnd a definit alfabetul Morse.
n codul Huffman, frecvena de apariie a caracterelor din textul surs, trebuie cunoscut sau estimat. Apoi, se asociaz
fiecrui simbol o secven de bii unic, care este definit utiliznd un arbore binar.
Un cod Huffman este construit astfel:
- se ordoneaz descresctor, dup frecven sau probabilitatea de apariie, simbolurile din textul surs;
- se consider fiecare simbol un nod n arbore, fiecrui nod fiindu-i asociat o probabilitate (frecvena) de apariie;
- se leag dou noduri cu probabilitatea de apariie cea mai mic, ntr-un nod a crui probabilitate este dat de suma
probabilitilor celor dou noduri acest proces se ncheie n momentul n care rmne un nod nelegat.
Rezultatul acestei operaii este un arbore binar, n care ramura stng a unui nod printe are eticheta ' 0 ', iar ramura din
dreapta, eticheta ' i ' .
S presupunem c textul nostru iniial este format din 40 de caractere, utiliznd un alfabet din 8 simboluri; frecvenele de
apariie ale fiecrui simbol, sunt calculate ca raport ntre numrul de apariii a simbolului respectiv i numrul total de caractere ale
textului.
n tabelul de mai jos, presupunem numrul de apariii ale simbolurilor i n funcie de acest numr calculm numrul total de
bii pe care l ocup simbolul respectiv, n reprezentarea normal (8 bii/caracter).
Varianta I-a de construire a codului Huffman
Simbol Nr. de apariii simbol Total nr. de bii pentru un
simbol (reprez. normal)
Total nr. de bii pentru un
simbol (cod Huffman)
0
1
2
3
4
5
6
7
12
8
6
5
4
3
2
0
96
64
48
40
32
24
16
0
12
16
18
20
20
18
14
0
Total 40 320 118
20% 22
12% 11
10% 11
100 % 11
70 % 77
50 % 55
35 % 33
23% 22
13 % 11
5 % 55
000
000
000
000
000
000
000
111
111
111
111
111
111
111
1111111 11
000
10 11
110 11
1110 11
11110 11
111110 11
1111110 11
000
111
222
333
444
555
666
777
30% 33
15% 11
8% 88
5% 55
0% 00
000
100% 11
111111 11
000
110 11
100 11
101 11
1110 11
11110 11
000
111
222
30% 33
20% 22
15% 11
12% 11
10% 11
8% 88
5% 55
0% 00
333
444
555
666
777
000
000
111
70% 77
43% 44
111
000
111
111
000
000
111
111
23% 22
13% 11
5% 55
111110 11
000
111
27% 22
Dac ns, cuplam nodurile n felul urmtor (varianta a II-a):
20% 22
12% 11
10% 11
100 % 11
70 % 77
50 % 55
35 % 33
23% 22
13 % 11
5 % 55
000
000
000
000
000
000
000
111
111
111
111
111
111
111
1111111 11
000
10 11
110 11
1110 11
11110 11
111110 11
1111110 11
000
111
222
333
444
555
666
777
30% 33
15% 11
8% 88
5% 55
0% 00
000
100% 11
111111 11
000
110 11
100 11
101 11
1110 11
11110 11
000
111
222
30% 33
20% 22
15% 11
12% 11
10% 11
8% 88
5% 55
0% 00
333
444
555
666
777
000
000
111
70% 77
43% 44
111
000
111
111
000
000
111
111
23% 22
13% 11
5% 55
111110 11
000
111
27% 22
vom obine:
Simbol Nr. de apariii
simbol
Total nr. de bii pentru un
simbol (reprez. normal)
Total nr. de bii pentru un simbol
(cod Huffman)
0
1
2
3
4
5
6
7
12
8
6
5
4
3
2
0
96
64
48
40
32
24
16
0
12
24
18
15
16
15
12
0
Total 40 320 112
observm c am obinut un numr total de bii mai mic, dect n prima variant, iar diferena este cu att mai mare, cu ct avem
texte de lungime mai mari.
Observm, c pe lng faptul c codul Huffman folosete n medie, un numr de bii mai mic dect codul ASCII pentru
reprezentarea unui caracter, mai are proprietatea c secvena binar asociat fiecrui simbol, nu este prefixul unui alt simbol i de
aceea, secvenele de bii sunt concatenate fr s se foloseasc nici o punctuaie de delimitare a acestora.

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