12.1. Tip abstract de dat. Prin tip dc datc sc n clcgc o mul imc dc valori, D, care formeaz domeniul tipului, mpreun cu o mul imc dc opcratori pc accst domcniu. n cazul cnd elementele domeniului sunt valori compuse din mai multe componente atomicc, tipul dc datc ob inut sc numctc tip dc datc structurat, sau structur de date. Un programator poate s-i dcIincasc propriile tipuri de date de care are nevoie n programul su. Opcra iilc cxistcntc n accstc noi tipuri dc datc sunt n primul rnd cele existente asupra componentelor. n structura definit de programator, ca entitate de sine stttoare exist ns doar operatorul de atribuire. Adcsca programatorul arc ncvoic dc opcra ii propriu-zisc. Tipul abstract de date (prescurtat TAD) este un astfel de tip, definit de om n urma unui proces de abstractizare. El este precizat prin: - domeniul TAD; - opcratorii dcIini i n accst domcniu. Nu intereseaz cum se reprezint clcmcntclc domcniului n calculator i nici cum se execut opcratorii asupra diIcri ilor opcranzi posibili. Pentru a specifica un TAD este necesar s precizm cele dou elemente alc tipului: domcniul i opcra iilc. Domcniul cstc prccizat ca o mul imc matcmatic, D. Pentru a spcciIica o opcra ic o este necesar s dcIinim matcmatic opcra ia o. n gcncral, sprc dcoscbirc dc opcra ia matcmatic, n programarc opcra ia o nu cstc o aplica ic total; ea are sens numai pentru anumite elemente din D. Valorile pcntru carc opcra ia o are sens satisfac un predicat numit prccondi ic pcntru 92 opcra ia o. Rezultatul efecturii opcra ici o depinde de operanzi, este legat de accti opcranzi, lcgtur precizat cu ajutorul unci postcondi ii, dat printr-un predicat . Exemplul 3.1.1. S specificm un TAD "numUUD LRQDO". Domeniul acestui TAD const din mul imca numcrclor ra ionalc, notat prin Q: Q = {(m,n) mZ, nN + , m,n prime ntre ele}. n aceast mul imc vom spcciIica urmtoarclc opcra ii: Opcra ia "Adun(q1,q2,q)": { q := q1 + q2 } Prccondi ia: q1, q2 Q ; Postcondi ia: q q1 q2 . Opcra ia "Scad(q1,q2,q)": { q := q1 - q2 } Prccondi ia: q1, q2 Q ; Postcondi ia: q q1 - q2 . Opcra ia "Inmult(q1,q2,q)": { q := q1 * q2 } Prccondi ia: q1, q2 Q ; Postcondi ia: q q1*q2. Opcra ia "Divid(q1,q2,q)": { q := q1 : q2 } Prccondi ia: q1, q2 Q i q20; Postcondi ia: q q1/q2. 93 Opcra ia "Atribc(sus,jos,q)"; { q:= sus/jos} Prccondi ia: sus Z, jos N i jos0; Postcondi ia: q sus/jos. Opcra ia "Citcstc(q)"; {q:= numr ra ional citit} Prccondi ia: dc la tastatur se introduce un numr ra ional ca pcrcchc (numrtor, numitor). Postcondi ia: q numrul ra ional citit. Opcra ia "Tiparcstc(q)"; Sc aIicaz numrul q} Prccondi ia: q Q Postcondi ia: sc aIicaz pe ecran numrul q Rcla ia "Estczcro(q)"; { Este q egal cu zero ?} Prccondi ia: q Q Postcondi ia: Dac q=0 atunci Estezero=TRUE altfel Estezero=FALSE sfdac. Rcla ia "Egal(q1,q2)"; { Este q1 egal cu q2 ?} Prccondi ia: q1, q2 Q Postcondi ia: Dac q1=q2 atunci Egal=TRUE altfel Egal=FALSE sfdac. Rcla ia "Maimarc(q1,q2)"; { Este q1 mai mare dect q2 ?} Prccondi ia: q1, q2 Q Postcondi ia: Dac q1>q2 atunci Maimare=TRUE altfel Maimare=FALSE sfdac. 94 Func ia "Intrcg(q)"; { Partea ntreag a lui q} Prccondi ia: q Q Postcondi ia: Intrcg partca ntrcag a lui q. Un tip abstract de date trebuie s con in suIicicntc opcra ii pcntru a Ii util. El trebuie s permit crearea oricrei valori din domeniul tipului. Trebuie s cxistc suIicicntc opcra ii dc tcstarc pcntru a putca Ii vcriIicatc toatc prccondi iilc opcra iilor. Trcbuic conccputc suIicicntc opcra ii pcntru ca programatorul s aib acces la oricare din componentele din care e compus acest tip abstract de date. Dcci tipurilc dc opcra ii pc carc lc con inc un TAD sunt: - opcra ii dc intrarc-icirc; - opcra ii dc construirc dc valori din domcniul tipului; - opcra ii dc convcrsic (a unor valori din altc tipuri dc datc) n valori dc accst tip; - opcra ii dc tcstarc a unor condi ii; - opcra ii dc sclcctarc a unor componcntc din carc c construit accst tip dc datc. n cazul TAD "numr ra ional" dcIinit mai sus, opcra iilc dc intrarc-icirc sunt "Citeste" i "Tipareste", opcra ia "Atribc" cstc constructor, opcra ia "Intreg" este o conversie, "Estezero", "Egal" i "Maimare" sunt opcra ii dc tcstarc, iar "Adun", "Scad", "Inmult" i "Divid" sunt opcra iilc aritmcticc cunoscutc. Printrc avantajclc Iolosirii tipurilor abstractc dc datc mcn ionm specificarea exact, indcpcndcn a implcmcntrii, ascundcrca inIorma ici, simplitatc i intcgritatc. Prin abstractizarc nc putcm conccntra asupra propriet ilor cscn ialc i nu asupra rcprczcntrii i implcmcntrii; accentul cade asupra specificrii tipului abstract de date. Utilizatorul se va folosi doar de aceast spcciIicarc, cl nu vcdc rcprczcntarca i nici modul dc implcmcntarc a opcra iilor. Tipurilc abstractc dc datc constituic unul din mijloacclc carc pcrmit o abordare sistematic i prin a cror utilizare se ajunge la realizarea unor module 95 corcctc i rcIolosibilc. Mai mult, accstc modulc sc pot organiza n bibliotcci utilc, ducnd la crctcrca productivit ii n programarc. 12.2. Uniti de program n Pascal. Prin unitate de program (Unit) Pascal nelegem o grupare de declaraii (constante, tipuri, variabile i subprograme) i eventual o seciune de iniializare. Un unit este compus dintr-o parte de interfa (Interface) i una de implementare (Implementation). Interfaa const din acele elemente ale unitii care sunt disponibile n exterior. Partea de implementare nu este accesibil n afara unitii i ea const din constante, tipuri de date, variabile, funcii, proceduri i instructiuni (toate acestea fiind locale) care sunt referite n funciile i procedurile descrise n interfa. Ea este invizibil din alte uniti de program. Forma general a unei uniti este urmtoarea : Unit <Nume_Unitate>; Interface <List _declara ii_globale> Implementation <List _declara ii_locale> [ Begin {opional} <Secven _de_ini ializare> ] End. n lista de declaraii care urmeaz dup Interface, se definesc constante, tipuri de dat, variabile, funcii i proceduri, accesibile altor uniti care folosesc aceast unitate de program. n aceste unitti, elementele declarate n seciunea Interface devin globale, putnd fi folosite ca orice variabile globale dintr-un program Pascal, spre deosebire de elementele declarate n seciunea Implementation. Acestea din urma ramn locale i nu sunt accesibile n afara 96 unitii n care sunt declarate. Secven a de ini ializare conine instruciuni care vor fi executate implicit naintea programului principal n scopul unor iniializri. Un program sau o unitate de program care dorete s foloseasc un Unit trebuie s precizeze acest lucru printr-o declaraie Uses <List _unit i_utilizate>. Pe lng unitile de program pe care i le scrie utilizatorul, acesta mai poate folosi cteva uniti standard oferite de mediul Turbo Pascal. Menionm urmtoarele uniti: System - conine proceduri i funcii de baz, predefinite, din Turbo Pascal; Crt - conine constante, funcii, proceduri, etc. de lucru cu ecranul i tastatura; Graph - conine constante, variabile, tipuri de dat, funcii i proceduri grafice; Dos - conine subprograme de lucru cu fiiere. System este inclus automat n orice program, fr a mai fi necesar clauza Uses. Primul exemplu prezentat n continuare apeleaz Unitul Rational pentru calculul unei expresii. Aici se poate vedea ct de simpl este realizarea unui astfel de program avnd la dispoziie acest tip. n acest exemplul s-a reuit ca operaiile de intrare-ieire s fie cele obinuite ( Read / Write ). Program Numere__Rationale; { x+y y+z z+x } Uses Rational; { E = ----- * ----- * ----- } Var x,y,z : Rationale; { x-y y-z z-x } Begin { x,y,z e Q (de forma p/q, q<>0) } Write ( x : ); Readln (x); Write ( y : ); Readln (y); Write ( z : ); Readln (z); Writeln ( E = , ProdQ( ProdQ ( ImpcQ(AdunQ(x,y),ScadQ(x,y) ), ImpcQ(AdunQ(y,z),ScadQ(y,z)) ), ImpcQ (AdunQ(z,x),ScadQ(z,x)))); Readln 97 End. Implementarea acestui tip este descris n continuare. Se poate observa c s-a reuit ca operaiile de intrare - ieire s fie cele standard i de asemenea operaiile aritmetice s fie funcii (nu proceduri) reprezentnd datele prin siruri de caractere (String). Tipul Q, care este de fapt perechea (numrtor, numitor) este ascuns utilizatorului, iar conversiile necesare de asemenea (TransfQ/R). Operaiile fiind cele elementare, binecunoscute din matematic, considerm c unitatea de program care urmeaz se poate nelege uor, fr alte explicaii. Unit Rational; Interface Type Rationale = String [20]; Func ion AdunQ ( a,b : Rationale) : Rationale; Func ion ScadQ ( a,b : Rationale) : Rationale; Func ion ProdQ ( a,b : Rationale) : Rationale; Func ion ImpcQ ( a,b : Rationale) : Rationale; Func ion InversQ ( a : Rationale) : Rationale; Implementation Type Q = Record Numarator, Numitor : Integer End; Func ion Cmmdc (a,b:Integer) : Integer; { Alg. Euclid recursiv } Begin If b=0 Then Cmmdc := a Else Cmmdc := Cmmdc (b, a Mod b) End; Func ion Cmmmc (a,b:Integer) : Integer; Begin 98 Cmmmc := a*b Div Cmmdc (a,b) End; Procedure Simplific ( Var x : Q); Var p:Integer; Begin With x Do Begin p:=Cmmdc(Numarator,Numitor); If p>1 Then Begin Numarator:=Numarator Div p; Numitor :=Numitor Div p End; If Numitor<0 Then Begin Numarator:= - Numarator; Numitor := - Numitor End End End; Procedure TransfQ ( s:Rationale; Var x : Q ); { String Q } Var p,q:Integer; Begin With x Do Begin { s de forma numarator/numitor , de ex. 3/2 } Val (s,Numarator,p); { p = poz. car / } Val (Copy(s,1,p-1),Numarator,q); Val (Copy(s,p+1,Length(s)-p),Numitor,q); If Numitor=0 Then Begin Write ('<',s,'>',' Numitor=0'); Readln End; Simplific (x) End End; Func ion TransfR ( x : Q ) : Rationale; { Q String } Var m, n : String; Begin 99 With x Do Begin Str (Numarator, m); Str (Numitor, n) End; TransfR:=m+/+n End; Procedure TipQ ( x : Q ); { Tipareste (q) } Begin With x Do Write (Numarator,/,Numitor); End; Func ion AdunQ ( a,b : Rationale) : Rationale; { a+b } Var x,y, z : Q; Begin TransfQ(a,x); TransfQ(b,y); {z:=x+y} With z Do Begin Numitor := Cmmmc (x.Numitor,y.Numitor); Numarator := x.Numarator * (Numitor Div x.Numitor)+ y.Numarator * (Numitor Div y.Numitor) End; Simplific(z); AdunQ:=TransfR(z) End; Func ion ScadQ ( a,b : Rationale ) : Rationale; { a-b } Var y:Q; Begin TransfQ(b,y); With y Do Numarator := -Numarator; { a+(-b)} b:=TransfR(y); ScadQ:=AdunQ (a,b) End; Func ion ProdQ ( a,b : Rationale) : Rationale; { a*b } Var x,y, z:Q; Begin TransfQ(a,x); TransfQ(b,y); { z:= x*y } With z Do Begin Numarator := x.Numarator * y.Numarator; Numitor := x.Numitor * y.Numitor 100 End; Simplific (z); ProdQ:=TransfR(z) End; Func ion InversabQ ( a : Rationale ) : Boolean; {Numarator <> 0} Var x:Q; Begin TransfQ(a,x); InversabQ:=x.Numarator<>0; End; Func ion InversQ ( a : Rationale ) : Rationale; { m/n n/m } Var x : Q; n : Integer; Begin TransfQ (a,x); With x Do Begin If InversabQ(a) Then Begin n := Numarator; Numarator:= Numitor; Numitor := n End; End; InversQ:=TransfR(x) End; Func ion ImpcQ ( a,b : Rationale) : Rationale; { a / b = a * 1/b} Begin If InversabQ (b) Then ImpcQ:=ProdQ (a,InversQ(b)) Else Write ( Operatie ilegala (:0) ) End; { Nu are secventa de initializare } End. 101 Al doilea exemplu prezntat n cele ce urmeaz se refer la TAD num r natural n precizie mrit. Avnd aceast aritmetic la dispoziie se poate uor extinde pentru numere ntregi prin adugarea semnului (+ sau ), iar apoi operaiile se reduc la operaii cu numere naturale (lund n considerare i semnul numerelor pentru care se efectueaz operaia). Programul Pascal care utilizeaz numere naturale n precizie marit, calculeaza C.m.m.d.c. (a,b) , apelnd operaia de comparare (<) i diferena a dou numere: Program Cmmdc_Natural_Marit; Uses Prec_Mar; Var a, b : Natural; Begin Write ( Dati a : ); Readln (a); Write ( Dati b : ); Readln (b); { Date a,b } While a<>b Do { Cat_Timp a <> b Executa } If MaiMic (a,b) Then b:=Dif(b,a) { Daca a<b Atunci b:=b-a } Else a:=Dif(a,b); { Altfel a:=a-b } Write ( Cmmdc = ,a); { Sf_Cat_Timp; } Readln { Rezultate a } End. Unit-ul apelat de acest program este descris n continuare. Acesta implementeaz operaii corespunztoare pentru : + , , < , >. Citire, Tip rire, Egalitate i Neegalitate nu au fost implementate pentru c se pot utiliza cele standard (Read, Write, = i <>). 102 Unit Prec_Mar; { Numar Natural Precizie Marit } Interface Const Dm = 10; Type Natural = String[Dm]; Func ion Suma (a,b:Natural) : Natural; Func ion Dif (a,b:Natural) : Natural; Func ion MaiMic (a,b:Natural) : Boolean; Func ion MaiMare (a,b:Natural) : Boolean; Implementation Func ion Tr (a,b:Char; Var t:Byte; Var c:Char):Byte; { a+b+t c i Tr } Const C0=Ord(0); Var s : Byte; Begin Tr:=0; s:= Ord(a)+Ord(b)-2*C0+t; If s>9 Then Begin Tr:=1; s:=s-10 End; c:= Chr(s+C0); End; Func ion Adun (a,b:Natural; t:Byte) : Natural; { a+b } Var n : Byte; Uc : Char; { Uc = Ultima Cifra } Begin n:=Length(a); { numarul de cifre } If a= Then If t=0 Then Adun:= Else Adun:=1 Else Adun:=Adun(Copy(a,1,n-1),Copy(b,1,n-1),Tr(a[n],b[n],t,Uc))+Uc End; Func ion Suma; { Suma a doua numere naturale a,b } Begin If a[0]<b[0] Then Suma:=Suma(b,a) Else If a[0]>b[0] Then Suma:=Suma(a,0+b) Else Suma:=Adun(a,b,0) End; Func ion Trs(a,b:Char; Var t:Byte; Var c:Char):Byte; {Tr. la scadere} Const C0=Ord(0); Var s : Integer; 103 Begin Trs:=0; s:= Ord(a)-Ord(b)-t; If s<0 Then Begin Trs:=1; s:=s+10 End; c:= Chr(s+C0); End; Func ion Scad (a,b:Natural; t:Byte) : Natural; { Scade : a-b-t } Var n : Byte; Uc : Char; Begin n:=Length(a); If a= Then Scad:= Else Scad:=Scad(Copy(a,1,n-1),Copy(b,1,n-1),Trs(a[n],b[n],t,Uc))+Uc End; Func ion Dif; Var d:Natural; Begin If MaiMic(a,b) Then Begin Dif:=0; Write (a,-,b, < 0 ); Readln End Else If a[0]>b[0] Then Dif:=Dif (a,0+b) Else Begin d:=Scad(a,b,0); { d:=a-b-0} While (Length(d)>1) And (d[1]=0) Do Delete(d,1,1); { Sterge 0 } Dif:=d End End; Func ion MaiMic; Begin MaiMic:=(a[0]<b[0]) Or ((a[0]=b[0]) And (a<b)) End; Func ion MaiMare; Begin MaiMare:=MaiMic(b,a) End; End. Propunem ca teme implementri pentru TAD Num r_Intreg, Complex i Polinom.