Listor... Ordnad lista Hur blir det om man skall sätta in och ta ut mitt i listan? Hur blir det om vi förutom referenser framåt också har referenser bakåt? Kan vi tänka oss annan organisation än linjära oordnade listor? Kan vi också ha olika element i listorna? Här ges koden för en Lista som är ordnad, homogen och diskontinuerlig. Först gränssnittet: Create Skapa ny tom lista Empty Är listan tom? Insert Sätt in ny post på rätt plats (sorterat efter nyckelvärde) Delete Ta bort post med visst nyckelvärde Member Finns det en post med visst nyckelvärde? Retrieve Återvinn information om post med visst nyckelvärde DA2001 (Föreläsning 15) Datalogi 1 Hösten 2010 1 / 20 DA2001 (Föreläsning 15) Datalogi 1 Hösten 2010 2 / 20 Ordnad lista... Ordnad lista typer Det behövs funktioner som jämför två nyckelvärden. Det räcker med lessthan och equal. Ex: FUNCTION lessthan(key1, key2: keytype): Boolean; lessthan := <key1 < key2> { med lämplig metod } FUNCTION equal(key1, key2: keytype): Boolean; equal := <key1 = key2> { med lämplig metod } Med de funktionerna kan element med nycklar som inte går att jämföra med vanliga jämförlseoperatorer ordnas enligt något kriterium som användaren väljer. keytype = { användardefinierad } key: keytype; { fler fält som definieras av användaren } entry: itemptr; next: elementptr; listptr = ^list; list = RECORD firstelement: elementptr; DA2001 (Föreläsning 15) Datalogi 1 Hösten 2010 3 / 20 DA2001 (Föreläsning 15) Datalogi 1 Hösten 2010 4 / 20
Ordnad lista - createlist och empty Ordnad lista member FUNCTION createlist: listptr; VAR tmp : listptr; New(tmp); tmp^.firstelement:= NIL; createlist := tmp FUNCTION empty(l: listptr): Boolean; empty := L^.firstElement = NIL; FUNCTION member(l: listptr; key: keytype): Boolean; VAR el: elementptr; el := L^.firstElement; WHILE (el <> NIL) AND lessthan(el^.entry^.key, key) DO el := el^.next; member := equal(el^.entry^.key, key) Med fallanalys: FUNCTION member(l: listptr; key: keytype): Boolean; FUNCTION search(el:elementptr):boolean; IF el = NIL THEN search := FALSE ELSE IF equal(key, el^.entry^.key) THEN search := TRUE ELSE IF lessthan(key, el^.entry^.key) THEN search := FALSE ELSE search := search(el^.next) member := search(l^.firstelement) DA2001 (Föreläsning 15) Datalogi 1 Hösten 2010 5 / 20 DA2001 (Föreläsning 15) Datalogi 1 Hösten 2010 6 / 20 Ordnad lista retrieve med fallanalys Ordnad lista delete med fallanalys FUNCTION retrieve(l:listptr; k:keytype):itemptr; VAR tmp : elementptr; FUNCTION find(el: elementptr): elementptr; IF el = NIL THEN find := NIL ELSE IF equal(k, el^.entry^.key) THEN find := el ELSE IF lessthan(k, el^.entry^.key) THEN find := NIL ELSE find := find(el^.next) tmp := find(l^.firstelement); IF tmp <> NIL THEN retrieve := tmp^.entry ELSE retrieve:= NIL FUNCTION delete( L:listPtr; k: keytype): listptr; FUNCTION delel(e: elementptr): elementptr; IF e <> NIL THEN IF equal(e^.entry^.key, k) THEN delel := e^.next; Dispose(e^.entry); Dispose(e) ELSE IF lessthan(e^.entry^.key, k) THEN delel := e; e^.next := delel(e^.next); ELSE delel := e ELSE delel := NIL; L^.firstElement := delel(l^.firstelement); delete := L DA2001 (Föreläsning 15) Datalogi 1 Hösten 2010 7 / 20 DA2001 (Föreläsning 15) Datalogi 1 Hösten 2010 8 / 20
Ordnad lista insert med fallanalys Varför speciella listelement ( containerelement )? FUNCTION insert(l:listptr; e: itemptr):listptr; FUNCTION insertel( e: elementptr): elementptr; WITH tmp^.entry^ DO IF e = nil THEN insertel := tmp ELSE IF lessthan(e^.entry^.key, key) THEN insertel := e; e^.next := insertel(e^.next) ELSE insertel := tmp; tmp^.next := e NEW(tmp); tmp^.next := nil; tmp^.entry := e; L^.firstElement := insertel(l^.firstelement); insert := L Ex: Antag att vi vill skapa en telefonkatalog som skall ge oss möjlighet att söka både i namnordning och efter telefonnummer: Med containerelement blir strukturen: Namn Telnr ADA,23 BEDA,13 EVA,31 DA2001 (Föreläsning 15) Datalogi 1 Hösten 2010 9 / 20 DA2001 (Föreläsning 15) Datalogi 1 Hösten 2010 10 / 20 Dubbellänkad lista... Variationer på listor Utan containerelement blir strukturen: Namn Telnr ADA,23 BEDA,13 EVA,31 BEDA,13 ADA,23 EVA,31 I detta (och många andra) fall är containerelement att föredra. Jag använder containerelement för att separera liststrukturen från det jag lagrar. Vi kan också ha länkar bakåt i listan: entry: itemptr; next, prev: elementptr; Övriga typdefinitioner oförändrade. Då erhålls en lista som är dubbellänkad. Det är ibland enklare att arbeta i en dubbellänkad lista men det krävs extra plats för ytterligare en länk. Vissa tillämpningar använder endast enkellänkad lista: stack och kö är två specialfall man måste titta närmare på DA2001 (Föreläsning 15) Datalogi 1 Hösten 2010 11 / 20 DA2001 (Föreläsning 15) Datalogi 1 Hösten 2010 12 / 20
De två viktiga specialfallen: stack och kö Stack och kö... När man utnyttjar enbart ena änden av en lista för både insättning och uttagning av element säger man sig ha en stack. En stack arbetar alltså efter principen sist in först ut (LIFO) och är en grundläggande datastruktur för olika datalogiska sammanhang. En kö har däremot principen först in först ut(fifo). enqueue dequeue push top bottom Stackar används vid (rekursiva) proceduranrop, hantering av blockstrukturer, beräkning av uttryck och avbrottshantering då man ofta sparar undan information på en stack för att senare kunna hämta information för att återta bearbetningen på rätt ställe i programmet. pop rear front Köer används vid simulering t.ex. för studium av väntetider och för att representera tid. Andra viktiga användningsområden är symboltabelluppbyggnad där antalet symboler i förväg inte är exakt känt. Vanligen inför man namn på början respektive slutet av listan. Dessa benämner vi För stack: top för toppen bottom för botten För kö: front för början rear för bakänden DA2001 (Föreläsning 15) Datalogi 1 Hösten 2010 13 / 20 DA2001 (Föreläsning 15) Datalogi 1 Hösten 2010 14 / 20 Stack Stack... En stack kan byggas på nästan samma sätt som en lista. Enda skillnaden är att insättning och borttagning alltid sker först i listan. key : integer; < user defined > entry : itemptr; next : elementptr stackptr = ^stack; stack = RECORD top : elementptr FUNCTION empty(s: stackptr): Boolean; empty := s^.top = NIL FUNCTION push(s: stackptr; i: itemptr): stackptr; New(tmp); tmp^.entry := i; tmp^.next := s^.top; s^.top := tmp; push := s DA2001 (Föreläsning 15) Datalogi 1 Hösten 2010 15 / 20 DA2001 (Föreläsning 15) Datalogi 1 Hösten 2010 16 / 20
Stack... Kö En kö är ett specialfall av lista där insättning alltid sker sist och borttagning alltid först (OBS! inte ett komplett program): FUNCTION pop(s: stackptr): itemptr; pop := NIL; IF empty(s) THEN error ELSE WITH s^ DO tmp := top; top := top^.next; pop := tmp^.entry; Dispose(tmp) key : integer; <user defined> entry : itemptr; next : elementptr; queueptr = ^queue; queue = RECORD front, rear : elementptr; VAR q : queueptr; DA2001 (Föreläsning 15) Datalogi 1 Hösten 2010 17 / 20 DA2001 (Föreläsning 15) Datalogi 1 Hösten 2010 18 / 20 Kö... Kö... FUNCTION enqueue(q: queueptr; e: itemptr): queueptr; WITH Q^ DO IF empty(q) THEN New(rear); front := rear ELSE New(rear^.next); rear := rear^.next rear^.entry := e; rear^.next := NIL enqueue := Q FUNCTION dequeue(q: queueptr): itemptr; VAR p: elementptr; dequeue := NIL; IF empty(q) THEN error ELSE WITH Q^ DO p := front; front := front^.next; dequeue := p^.entry; Dispose(p) FUNCTION empty(q: queueptr): Boolean; empty := Q^.front = NIL DA2001 (Föreläsning 15) Datalogi 1 Hösten 2010 19 / 20 DA2001 (Föreläsning 15) Datalogi 1 Hösten 2010 20 / 20