Poster Vi har ofta behov av att behandla klumpar av data som i sig är inhomogena men sett över ett helt register har klumparna lika struktur. TYPE car = RECORD model : 1900..2000; ndoors : 2..5; weight : 100..Maxint; cartype : (person, kombi, last); VAR mycar, yourcar : car; DA2001 (Föreläsning 14) Datalogi 1 Hösten 2010 1 / 25
Poster... Enskilda fält kan nås med s.k. punktnotation mycar.model := 2008; mycar.ndoors:= 3;... WriteLn(myCar.ndoors); IF yourcar.weight > mycar.weight THEN... yourcar := mycar; { alla fält kopieras } In och utmatning av hela poster kan INTE ske till/från terminalen. DA2001 (Föreläsning 14) Datalogi 1 Hösten 2010 2 / 25
Poster... Representation av komplexa tal: Program complex(input,output); TYPE complexnumber = RECORD re,im : real; VAR z1 : complexnumber; FUNCTION impart(z : complexnumber):real; impart:= z.im; z1.im:=3; z1.re:=2; WriteLn( Den imaginära delen är:,impart(z1):0); END. DA2001 (Föreläsning 14) Datalogi 1 Hösten 2010 3 / 25
Poster... När vi t.ex. adderar två komplexa tal får vi en ny post (RECORD) med resultatet i. För att konstruktorn skall kunna returnera resultatet måste det rymmas i ett ord. Det är INTE tillåtet att returnera hela poster! En lösning på problemet är att lämna en adress till en post. Hur representerar vi adresser? Program complex(input,output); TYPE complexpointer = ^complexnumber; { complexpointer är adress till objekt av typen complexnumber } complexnumber = RECORD re,im : real; VAR z1,z2 : complexpointer; { variabler som innehåller } { adresser till objekt av typen complexnumber } DA2001 (Föreläsning 14) Datalogi 1 Hösten 2010 4 / 25
Poster... Program complex(input,output); TYPE complexpointer = ^complexnumber; { complexpointer är adress till objekt av typen complexnumber } complexnumber = RECORD re,im : real; VAR z1,z2 : complexpointer; { variabler som innehåller } { adresser till objekt av typen complexnumber } New(z1); { skapa ett nytt objekt i minnet och } { låt z1 få dess adress } New(z2); z1^.im:=3; z1^.re:=2; z2^:=z1^; { posten kopieras } IF z1 <> z2 THEN z2:=z1; { adressen kopieras } Dispose(z2); { återlämna minnesutrymmet } END. DA2001 (Föreläsning 14) Datalogi 1 Hösten 2010 5 / 25
Poster... Statisk variabel: Den är deklarerad och har ett namn som används för att referera till variabeln. Det minnesutrymme som tilldelats vid ingången i ett block förblir reserverat under hela exekveringen av blocket. Ex. Heltalsvariabler, poster, osv. tal 2134 DA2001 (Föreläsning 14) Datalogi 1 Hösten 2010 6 / 25
Poster... Dynamisk variabel: Kan skapas och dödas under exekveringen. Den dynamiska variabeln har inget namn utan man använder en referensvariabel för att referera till den. tal 2134 DA2001 (Föreläsning 14) Datalogi 1 Hösten 2010 7 / 25
Poster... Hur är de deklarerade? Statisk variabel: VAR tal: Integer; tal:=2134;... DA2001 (Föreläsning 14) Datalogi 1 Hösten 2010 8 / 25
Poster... Dynamisk variabel: TYPE heltal = ^heltalstyp; heltalstyp = RECORD value:integer; VAR tal : heltal; New(tal); tal^.value := 2134;... DA2001 (Föreläsning 14) Datalogi 1 Hösten 2010 9 / 25
Poster... Operationer: Skapa en ny dynamisk variabel New(p); ny variabel av p:s typ, p sätts att referera till den nya variabeln. Utplåna en dynamisk variabel om p refererar till en dynamisk variabel så gör: Dispose(p); att minnesutrymmet, som p upptar, friställs för återanvändning och alla värden går förlorade. p har inget eget värde efter det att satsen exekverats. DA2001 (Föreläsning 14) Datalogi 1 Hösten 2010 10 / 25
Poster... Tilldelning: p := tilldelning av referens. p^ := tilldelning av värde. Det finns bara en referenskonstant: NIL = inget objekt NEW(p); p := NIL; gör att en dynamisk variabel skapas i minnet. Då man sedan släpper referensen kan man aldrig mer komma åt objektet. Objektet tar så mycket minnesutrymme i anspråk som postdefinitionen föreskriver. DA2001 (Föreläsning 14) Datalogi 1 Hösten 2010 11 / 25
Poster... PROGRAM complex(input,output); TYPE complexpointer = ^complexnumber; complexnumber = RECORD re, im : Real VAR z,w: complexpointer; FUNCTION add(z1, z2: complexpointer): complexpointer; VAR w:complexpointer; New(w); w^.re := z1^.re + z2^.re; w^.im := z1^.im + z2^.im; add := w New(z); New(w); Readln(z^.re, z^.im, w^.re, w^.im); z := add(z,w); Writeln(z^.re, z^.im) END. DA2001 (Föreläsning 14) Datalogi 1 Hösten 2010 12 / 25
Poster... När vi i Scheme har gjort listor har vi använt oss av box-pekar diagram för att rita upp listorna. Exempelvis (define minlista (list 1 2 3)) 1 2 3 Vi kan nu även i bygga upp en liknande struktur m.hj.a. pekare och poster. Vi kan skapa minnesutrymme och länka samman dessa med pekare. Det ger oss redskap för att bygga listor. Hur ska vi då lägga in data, arbeta med listor, ta bort element osv? DA2001 (Föreläsning 14) Datalogi 1 Hösten 2010 13 / 25
Pekare... PROGRAM ex; TYPE elementptr = ^element; element = RECORD entry: integer; next: elementptr VAR e1, e2 : elementptr; { strukturen skapas för listan } NEW(e1); NEW(e1^.next); NEW(e1^.next^.next); { tilldela värden i listan } e1^.entry := 1; e1^.next^.entry := 2; e1^.next^.next^.entry := 3; e1^.next^.next^.next := NIL; { hjälppekare sätts att peka i listan } e2 := e1^.next^.next END. DA2001 (Föreläsning 14) Datalogi 1 Hösten 2010 14 / 25
Pekare... NEW(e1); e1 entry next NEW(e1^.next); e1 entry next entry next NEW(e1^.next^.next); e1 entry next entry next entry next { tilldela värden i listan, med bl.a.: } e1^.next^.next^.next := NIL; e1 1 next 2 next 3 next NIL { hjälppekare sätts att peka i listan } e2 := e1^.next^.next; e1 e2 1 next 2 next 3 next NIL DA2001 (Föreläsning 14) Datalogi 1 Hösten 2010 15 / 25
Listor kan (i princip) byggas på två sätt Kontinuerliga listor Alla element ligger i en följd i datorns minne Index är ett offset från första komponenten Kräver att utrymme kan reserveras då programmet startas Kan inte växa (eller krympa) dynamiskt (Den typ av listor jag inledningsvis diskuterade tillhör inte denna kategori) Diskontinuerliga listor Elementen läggs där det finns plats i minnet, inte säkert i följd Man måste hålla reda på var nästa element finns så förutom elementet själv måste man lagra adressen till nästa element Fördelen är att listan kan växa och krympa dynamiskt Man kan sedan ha homogena eller inhomogena listor: I en homogen lista är alla element av samma typ. I en inhomogen lista är elementen av olika typ. I Scheme kan man ha alla sorter I kan man bara ha homogena listor men både kontinuerliga och diskontinuerliga. DA2001 (Föreläsning 14) Datalogi 1 Hösten 2010 16 / 25
Oordnad lista... Med de verktyg vi har kan vi konstruera en listhanterare som kan hantera oordnade element. Vi behöver kunna sätta in element, ta bort element och navigera i listan (vandra framåt och bakåt). Därför ska vi skriva funktionerna insert, delete, settofirst next och previous. Dessutom behöver vi kunna hämta element och testa om vi navigerar i listan. Till det skriver vi funktionerna retrieve och isonlist? Men vi börjar med typspecifikationerna: DA2001 (Föreläsning 14) Datalogi 1 Hösten 2010 17 / 25
Oordnad lista... TYPE itemptr = ^item; item = RECORD <user defined> elementptr = ^element; element = RECORD entry : itemptr; next : elementptr listptr = ^list; list = RECORD first, cursor : elementptr VAR L : listptr; DA2001 (Föreläsning 14) Datalogi 1 Hösten 2010 18 / 25
Oordnad lista... Om man vill slippa skriva L^. för varje fält (och dessutom snabbare komma åt fälten) kan man skriva: WITH L^ DO { här når man fälten i L^ utan punktnotation }; WITH q1 DO WITH q2 DO { om q1 och q2 har överlappande fältnamn } { så kommer man åt q2:s fält } WITH q1, q2 DO { fälten i q1 och q2 tillgängliga }; DA2001 (Föreläsning 14) Datalogi 1 Hösten 2010 19 / 25
Oordnad lista... insert sätter in först i listan. Man skulle kunna tänka sig att sätta in på platsen för cursor eller sist. (Fundera över hur man gör då) FUNCTION insert(l: listptr; e: itemptr): listptr; VAR p : elementptr; NEW(p); p^.entry := e; p^.next := L^.first; L^.first := p; insert := L DA2001 (Föreläsning 14) Datalogi 1 Hösten 2010 20 / 25
Oordnad lista... Funktionen delete tar bort det element som cursor pekar på genom att sätta in listans första element på platsen för cursor och sedan ta bort listans första element. delete bevarar alltså inte listans ordning. FUNCTION delete(l: listptr): listptr; VAR tmp : elementptr; delete := L; IF L^.cursor <> NIL THEN WITH L^ DO cursor^.entry := first^.entry; tmp := first; first := first^.next; Dispose(tmp) END ELSE error DA2001 (Föreläsning 14) Datalogi 1 Hösten 2010 21 / 25
Oordnad lista... settofirst sätter cursor att peka på det första elementet i listan. OBS! att om listan är tom förblir värdet på cursor = NIL. FUNCTION settofirst(l: listptr): listptr; L^.cursor := L^.first; settofirst := L; DA2001 (Föreläsning 14) Datalogi 1 Hösten 2010 22 / 25
Oordnad lista... Funktionen next flyttar cursor ett steg framåt om cursor pekar på ett element i listan, annars händer ingenting. FUNCTION next(l:listptr): listptr; IF L^.cursor <> NIL THEN WITH L^ DO cursor := cursor^.next; next:=l; DA2001 (Föreläsning 14) Datalogi 1 Hösten 2010 23 / 25
Oordnad lista... previous sätter cursor att peka på elementet före det som cursor just nu pekar på. Eftersom det inte finns pekare till föregående element måste man utgående från det första elementet i listan hitta det, vars next-pekare pekar på samma element som cursor gör. FUNCTION previous(l: listptr): listptr; FUNCTION findprev(anelement: elementptr): elementptr; WHILE anelement^.next <> L^.cursor THEN anelement := anelement^.next; findprev := anelement WITH L^ DO IF (cursor = first) OR (cursor = NIL) THEN cursor := NIL ELSE cursor := findprev(first); previous := L DA2001 (Föreläsning 14) Datalogi 1 Hösten 2010 24 / 25
Oordnad lista... retrieve återsänder en pekare till den information som finns lagrad i det listelement som cursor pekar på, men om cursor inte pekar på något element återsänds NIL. FUNCTION retrieve( L:listPtr): itemptr; WITH L^ DO IF cursor <> NIL THEN retrieve := cursor^.entry ELSE retrieve := NIL isonlist kontrollerar om cursor pekar på något element i listan eller inte. FUNCTION isonlist(l: listptr): Boolean; isonlist := L^.cursor <> NIL DA2001 (Föreläsning 14) Datalogi 1 Hösten 2010 25 / 25