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);
END;
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
BEGIN
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
Pascal
Poster . . .
Representation av komplexa tal:
Program complex(Input,Output);
TYPE
complexNumber = RECORD re,im : real;
END;
VAR z1 : complexNumber;
FUNCTION imPart(z : complexNumber):real;
BEGIN
imPart:= z.im;
END;
BEGIN z1.im:=3;
z1.re:=2;
WriteLn(’Den imaginära delen är: ’,imPart(z1):0);
END.
Pascal
Poster . . .
I När vi t.ex. adderar två komplexa tal får vi en ny post (RECORD) med resultatet i.
I För att konstruktorn skall kunna returnera resultatet måste det rymmas i ett ord.
I Det är INTE tillåtet att returnera hela poster!
I En lösning på problemet är att lämna en adress till en post.
I Hur representerar vi adresser?
Program complex(Input,Output);
TYPE complexPointer = ^complexNumber;
{ complexPointer är adress till objekt av typen complexNumber } complexNumber = RECORD
re,im : real;
END;
VAR z1,z2 : complexPointer; { variabler som innehåller } { adresser till objekt av typen complexNumber }
Poster . . .
Program complex(Input,Output);
TYPE complexPointer = ^complexNumber;
{ complexPointer är adress till objekt av typen complexNumber } complexNumber = RECORD
re,im : real;
END;
VAR z1,z2 : complexPointer; { variabler som innehåller } { adresser till objekt av typen complexNumber } BEGIN
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
Pascal
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
PP PP
PPPq
2134
Pascal
Poster . . .
Hur är de deklarerade?
Statisk variabel:
VAR tal: Integer;
BEGIN
tal:=2134;
...
Poster . . .
Dynamisk variabel:
TYPE heltal = ^heltalsTyp;
heltalsTyp = RECORD value:Integer;
END;
VAR tal : heltal;
BEGIN New(tal);
tal^.value := 2134;
...
DA2001 (Föreläsning 14) Datalogi 1 Hösten 2010 9 / 25
Poster . . . Operationer:
I Skapa en ny dynamisk variabel
New(p);ny variabel avp:s typ,psätts att referera till den nya variabeln.
I Utplåna en dynamisk variabel
omprefererar till en dynamisk variabel så gör:
Dispose(p);
att minnesutrymmet, sompupptar, friställs för återanvändning och alla värden går förlorade.
phar inget eget värde efter det att satsen exekverats.
DA2001 (Föreläsning 14) Datalogi 1 Hösten 2010 10 / 25
Pascal
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.
Pascal
Poster . . .
PROGRAM complex(Input,Output);
TYPE complexPointer = ^complexNumber;
complexNumber = RECORD re, im : Real END;
VAR z,w: complexPointer;
FUNCTION add(z1, z2: complexPointer): complexPointer;
VAR w:complexPointer;
BEGIN New(w);
w^.re := z1^.re + z2^.re;
w^.im := z1^.im + z2^.im;
add := w END;
BEGIN
New(z); New(w);
Readln(z^.re, z^.im, w^.re, w^.im);
z := add(z,w);
Writeln(z^.re, z^.im) END.
Poster . . .
I När vi i Scheme har gjort listor har vi använt oss av box-pekar diagram för att rita upp listorna.
I Exempelvis (define minLista (list 1 2 3))
1 2 3
I Vi kan nu även i Pascal bygga upp en liknande struktur m.hj.a. pekare och poster.
I Vi kan skapa minnesutrymme och länka samman dessa med pekare.
I Det ger oss redskap för att bygga listor.
I 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 END;
VAR e1, e2 : elementPtr;
BEGIN
{ 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
Pascal
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;
e2
e1 1 next 2 next 3 next NIL
Pascal
Listor kan (i princip) byggas på två sätt
I Kontinuerliga listor
I Alla element ligger i en följd i datorns minne
I Index är ett offset från första komponenten
I Kräver att utrymme kan reserveras då programmet startas
I Kan inte växa (eller krympa) dynamiskt
I (Den typ av listor jag inledningsvis diskuterade tillhör inte denna kategori)
I Diskontinuerliga listor
I Elementen läggs där det finns plats i minnet, inte säkert i följd
I 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
I Fördelen är att listan kan växa och krympa dynamiskt
I Man kan sedan ha homogena eller inhomogena listor:
I I en homogen lista är alla element av samma typ.
I I en inhomogen lista är elementen av olika typ.
I I Scheme kan man ha alla sorter
I I Pascal kan man bara ha homogena listor men både kontinuerliga och diskontinuerliga.
Oordnad lista . . .
I Med de verktyg vi har kan vi konstruera en listhanterare som kan hantera oordnade element.
I Vi behöver kunna sätta in element, ta bort element och navigera i listan (vandra framåt och bakåt).
I Därför ska vi skriva funktionernainsert, delete, setToFirst nextoch previous.
I Dessutom behöver vi kunna hämta element och testa om vi navigerar i listan. Till det skriver vi funktionernaretrieveochisOnList?
I 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>
END;
elementPtr = ^element;
element = RECORD entry : itemPtr;
next : elementPtr END;
listPtr = ^list;
list = RECORD
first, cursor : elementPtr END;
VAR L : listPtr;
DA2001 (Föreläsning 14) Datalogi 1 Hösten 2010 18 / 25
Pascal
Oordnad lista . . .
Om man vill slippa skrivaL^.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 };
Pascal
Oordnad lista . . .
insertsätter in först i listan. Man skulle kunna tänka sig att sätta in på platsen förcursoreller sist. (Fundera över hur man gör då)
FUNCTION insert(L: listPtr; e: itemPtr): listPtr;
VAR p : elementPtr;
BEGIN NEW(p);
p^.entry := e;
p^.next := L^.first;
L^.first := p;
insert := L END;
Oordnad lista . . .
Funktionendeletetar bort det element somcursorpekar på genom att sätta in listans första element på platsen förcursoroch sedan ta bort listans första element.deletebevarar alltså inte listans ordning.
FUNCTION delete(L: listPtr): listPtr;
VAR tmp : elementPtr;
BEGIN
delete := L;
IF L^.cursor <> NIL THEN WITH L^ DO BEGIN cursor^.entry := first^.entry;
tmp := first;
first := first^.next;
Dispose(tmp) END ELSE error END;
DA2001 (Föreläsning 14) Datalogi 1 Hösten 2010 21 / 25
Oordnad lista . . .
setToFirstsättercursoratt 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;
BEGIN
L^.cursor := L^.first;
setToFirst := L;
END;
DA2001 (Föreläsning 14) Datalogi 1 Hösten 2010 22 / 25
Pascal
Oordnad lista . . .
Funktionennextflyttarcursorett steg framåt omcursorpekar på ett element i listan, annars händer ingenting.
FUNCTION next(L:listPtr): listPtr; BEGIN IF L^.cursor <> NIL THEN WITH L^ DO
cursor := cursor^.next;
next:=L;
END;
Pascal
Oordnad lista . . .
previoussättercursoratt peka på elementet före det somcursorjust 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, varsnext-pekare pekar på samma element somcursorgör.
FUNCTION previous(L: listPtr): listPtr;
FUNCTION findPrev(anElement: elementPtr): elementPtr;
BEGIN
WHILE anElement^.next <> L^.cursor THEN anElement := anElement^.next;
findPrev := anElement END;
BEGIN WITH L^ DO
IF (cursor = first) OR (cursor = NIL) THEN cursor := NIL
ELSE
cursor := findPrev(first);
previous := L END;
Oordnad lista . . .
retrieveåtersänder en pekare till den information som finns lagrad i det listelement somcursorpekar på, men omcursorinte pekar på något element återsändsNIL.
FUNCTION retrieve( L:listPtr): itemPtr;
BEGIN
WITH L^ DO
IF cursor <> NIL THEN retrieve := cursor^.entry ELSE retrieve := NIL
END;
isOnListkontrollerar omcursorpekar på något element i listan eller inte.
FUNCTION isOnList(L: listPtr): Boolean;
BEGIN
isOnList := L^.cursor <> NIL END;
DA2001 (Föreläsning 14) Datalogi 1 Hösten 2010 25 / 25