1 Modul 2 ADTer 1.1 Definition En ADT beskriver en datatyp. är en specifikation som är oberoende av implementation. innefattar typen, operationerna och egenskaperna. Egenskaperna beskrivs m h a operationerna, i vårt fall innebär det att vi använder kontrakt. beskriver de delar av ett verkligt objekt man är intresserad av. implementeras i C++ lättast och bäst med klasser kan implementeras i vilket programspråk som helst. åstadkommer modularitet gör användandet av datatypen enklare. kan användas för att konstruera mjukvara redan innan den har implementerats. Verkligt objekt Abstraherat Implementerat All information Intressant Mappning till information datatyper
1.2 Vad menas med abstraktion? Abstraktion är ett mycket viktigt begrepp. Att abstrahera något innebär att man endast fokuserar på de delar som är intressanta. Det brukar vara enklast att exemplifiera abstraktion med ett exempel. Tänk dig en bil. Vad behöver du känna till för att kunna köra bilen? Jo, du behöver vara förtrogen med de reglage/instrument som finns för att köra bilen. Dessa utgör ett gränssnitt för en användare av bilen. Du behöver inte känna till hur bränsleinsprutningen fungerar, vilket oljetryck som är optimalt, hur kylvattnet cirkulerar eller hur kraftöverföringen till hjulen sker trots att dessa saker är viktiga för bilens funktion. Det räcker att du känner till att bilen accelererar om du trampar på gaspedalen, svänger när du vrider på ratten o s v, det är ointressant exakt hur det går till. Många detaljer angående bilens funktionssätt ingår inte i abstraktionen för hur man använder bilen. Bilens gränssnitt för föraren utgör en abstraktion av bilens totala funktionssätt. Det som föraren ser är alltså vad som är intressant för att kunna använda bilen. De som konstruerar bilen måste givetvis känna till funktionen för de delar de konstruerar. Ju mer detaljerad kunskap man måste ha, ju mindre är abstraktionen och vice versa. Låt oss nu ta ett exempel för en klass, skriven i exempelvis C++. Den som implementerar klassen måste sätta sig in i hur saker och ting ska göras. Den som använder klassen ska inte behöva veta hur den är implementerad, endast vad den representerar och hur den kan användas. Ytterligare ett perspektiv då man skapar klasser utifrån verkliga objekt är att man endast tar med de delar som är intressanta. Säg att vi med mjukvara vill modellera en person, då skulle vi skapa en klass "Person". Emellertid kommer vi inte att försöka modellera alla tänkbara egenskaper och beteenden för en riktig person. Vi kommer att välja de delar som är intressanta utifrån vad vi ska ha vår klass "Person" till. Säg att klassen Person ingår i en applikation för en bank. Då kommer vi att välja egenskaper som personnummer, namn, bankkonto, o s v. Det vi väljer att modellera är en abstraktion av det verkliga personobjektet. Vi tar endast med vad som är intressant, givet ett visst perspektiv.
1.3 Olika representationer av ADTer Algebraisk / Axiomatisk representation hög abstraktionsnivå Pragmatisk representation medelmåttig abstraktionsnivå Implementerad representation låg abstraktionsnivå Algebraisk/Axiomatisk representation Pragmatisk representation Implementerad representation Vi kommer att fokusera på den pragmatiska representationen samt den implementerade representationen av ADTer. Nedan förklaras innebörden av begreppen närmare. Förklaringen av den algebraiska/axiomatiska representationen är ämnad som en ytlig orientering, den är inte fullständig enligt konstens alla regler.
1.3.1 Algebraisk/axiomatisk representation av en ADT Beskriver typen, operationerna och egenskaperna. på ett algebraiskt sätt utan att gå in på implementationen. Mängdlära används. Axiom uttrycker egenskaperna för ADTn m h a operationerna. Detta sätt används för att kunna beskriva ADTer på ett exakt och otvetydigt sätt. Ett kraftfullt och koncist sätt att uttrycka ADTer på men kan vara svårt att tillämpa från början. Används ganska sällan i böcker (Bertrand Meyer, som är känd inom OO, gör det t ex.) Exempel 1 Algebraisk/axiomatisk representation av ADTn List typ List operationer create: 0 L destroy L 0 insert: L E P L delete: L P L isempty: L B axiom isempty(create) = true isempty(insert(l, e, p)) = false delete(insert(l, e, p), p) = l förvillkor Pre(delete(l, p)) =!isempty(l) där L är mängden av alla listor E är mängden av alla element P är mängden av alla positioner B är mängden av alla booleska värden (true, false) 0 är tomma mängden
1.3.2 Pragmatisk representation av en ADT Beskriver typen, operationerna och egenskaperna. på ett informellt sätt utan att gå in på implementationen. Beskrivningar av egenskaper och operationer kan göras med t ex naturligt språk. Vi kommer att använda kontrakt för att beskriva operationerna. Om det behövs en beskrivning utöver vad kontraktet ger ska en sådan läggas till. Denna typ av beskrivning är mer vanligt förekommande i böcker, även om kontrakt inte är alltför vanligt, tyvärr. Exempel 2 Pragmatisk representation av ADTn List Type (Typ) List Description: List is a finite ordered sequence of elements. Element is an element of a list. Properties (Egenskaper) A new list is empty, meaning that its size is 0. The list can store an undetermined number of elements. The elements are ordered but not sorted. Operations (Operationer) Description: Creates a new list Pre: true Post: a new empty list has been created, isempty() == true create() Description: Deletes a list Pre: true Post: The list has been deleted destroy() Description: Inserts a new element into a list Pre: 1 <= position <= size() + 1 Post: The element e has been inserted at the position "positon" in the list. The elements that were at positions >= "position" prior to the insertion are now at their old position + 1 insert(in: Element e, in: Integer position) Description: Removes an element from a list Pre: Define it! Post: Define it! remove(in: Integer position)
Description: Checks whether a list is empty or not Pre: true Post: result = true if the list is empty, false otherwise isempty(out: Boolean) Description: Checks whether an element is part of a list. Pre: Define it! Post: result = Define it! iselement(in:?, out: Boolean) Pre: Define it! Post: Define it! size(in:? out:?) Define it! More operations? Anmärkningar: List är en implicit parameter i alla operationer utom i create(). in betyder att det är en parameter till operationen, out betyder returtyp Kan fler operationer kan tänkas ingå, vilka? Beskrivningen är skriven på engelska, det går bra med svenska också. Men det är mer fördelaktigt att använda engelska, såväl för specifikationer av ADTer som för källkod. Varför? Där jag skrivit "Define it!" är det meningen att du ska definiera kontrakten. Gör så gott du kan utifrån de exempel som finns och de kunskaper du fått från kursen Programmeringsteknik. Där det står ett "?" är det meningen att du ska definiera eventuella parametrar och returtyper. 1.4 Olika kategorier av operationer: Creator - Tillverkare av en instans av en ADT, create() i exemplet ovan. Destructor - Destruerare av en instans av en ADT, destroy()i exemplet ovan. Transformer Förändrar en instans av en ADT på något sätt. Det finns två kategorier av transformerare, konstruktiva och destruktiva transformerare. insert(element e) är en konstruktiv transformerare eftersom den förändrar listan genom att utöka den. delete(element e) är en destruktiv transformerare eftersom den förändrar listan genom att förminska den. Inspector Inspekterar endast en instans av en ADT. Det finns två kategorier av inspektorer, de som frågar saker om instansen, kallade queries, och övriga som på annat sätt inspekterar den, kallade selectors. isempty() är ett exempel på en query inspector. Finns det ytterligare någon? En query operation ger alltid, som resultat, endera värdet true eller false, d v s ett booleskt värde. Det finns inget exempel ovan på en selector men man sklle kunna tänka sig en operation vid namn getelement()
1.5 Vanliga ADT:er Mängd - en oordnad samling element, duplikat förekommer inte Lista en ordnad ändlig sekvens av element, duplikat får förekomma Sorterad lista - lista där elementen är sorterade efter någon form av storleksordning Stack - en ordnad ändlig sekvens av element med LIFO-egenskap (Last In First Out) Kö - en ordnad ändlig sekvens av element med FIFO-egenskap (First In First Out) Detta är bara några exempel på vanliga ADT:er. I denna kurs kommer vi att titta på alla dessa utom den första, samt några till.
1.5.1 Mängd Egenskaper: Operationer: Ett antal element av samma sort Elementen kan inte sorteras. Varje element är unikt, d v s det kan endast förekomma en gång. Kan lagra ett obestämt antal element Skapa mängd Ta bort mängd Lägg till element Ta bort element Fråga om element finns i mängden. Fråga om antalet element i mängden Fler? Hur kan en mängd implementeras? T ex m h a en lista. 1.5.2 Stack Egenskaper: Operationer: En ordnad ändlig sekvens av element med LIFO-egenskap. Elementen är ordnade men inte sorterade. Kan lagra ett obestämt antal element. Skapa stack Ta bort stack Lägg till element i stacken (överst enligt LIFO) Ta bort element ur stacken. (överst enligt LIFO) Hämta översta elementet i stacken. (det enda som går att hämta enligt LIFO) Fråga om antalet element i stacken. Fler? Hur kan en stack implementeras? T ex m h a en lista. På vilket sätt kan en lista bidra för att implementera en stack? Vi kommer att titta mer på detta då vi går igenom ADTn stack. Man kan alltså ta en (eller flera) ADT(er) som är implementerade till hjälp för att implementera en annan ADT.
1.6 Carranos specifikation av ADTn lista På sidan 119 ses Carranos specifikation av ADTn List, eller som det står, pseudokod för operationerna. Denna specifikation är inte lika bra som den ovan eftersom den är ofullständig som ADT-specifikation, dessutom finns inte kontrakten explicit uttryckta. Egenskaper och kontrakt är inbakade i pseudokoden implicit, och så vill vi inte ha det. Vi vill att representationen av ADTn ska vara så tydlig som möjligt. Vi kommer att specificera ADTer enligt det exempel som finns ovan i kompendiet. För vidare kommentarer till kapitel 3 som handlar om ADTer, se läsanvisningarna. 1.7 Implementerad representation av en ADT Vad är fördelarna med att göra en pragmatisk beskrivning av en ADT? Har vi någon nytta av att ha gjort en pragmatisk representation av en ADT? Ja!!!!! Det finns flera fördelar: Det tvingar oss att tänka efter innan vi sätter oss ner och skriver kod. Därigenom kommer det att bli mycket enklare att implementera ADTn. I och med att vi gör en ADT så skapar vi en robust dokumentation. Detta kommer vi att ta upp lite senare i kursen. Om vi har gjort en bra pragmatisk beskrivning av ADTn kan den på ett förtjänstfullt sätt översättas till nästan vilket programspråk som helst. Exempel 3 Implementerad representation av ADTn List Vi ska alltså implementera ADTn List i språket C++. För att göra detta ska vi utgå från den pragmatiska beskrivningen i exempel 2 ovan. Klasser är C++ och andra objektorienterade språks sätt att definiera och implementera ADTer. Typen blir klassens namn Operationerna sätter man in i public-delen och anpassar dem till språket. Sen måste man också fundera över egenskaperna. Vad säger de oss? a) En nyskapad lista är tom b) Listan kan lagra ett obestämt antal element. c) Elementen är ordnade men inte sorterade a) säger att kontruktorn helt enkelt ska skapa en tom lista, b) säger att vi ska använda en länkad lista. (Varför inte en arraybaserad lista?) c) utrycker egentligen två egenskaper, att listan är ordnad innebär att varje element finns på en viss position. Att den inte är sorterad innebär att listan inte är ordnad med avseende på någon jämförelse av elementen. Exempel: Antag att vi har en lista som innehåller heltal som element. Listan är: 3, 66, 4, 1, 2, 2, 3, 44, 17 Listan är ordnad, d v s elementen finns i en viss ordning m a p var i listan de befinner sig. Exempelvis finns talet 4 på position 3 och talet 2 finns på position 5 och 6. Listan är dock inte sorterad, varken i stigande eller fallande ordning.
class List { public: typedef int Element; // Denna lista lagrar heltal som // element // Description: Creates a new list // Pre: true // Post: a new empty list has been created // In the ADT: create() List(); // Description: Deletes a list // Pre: true // Post: The list has been deleted //In the ADT: destroy() ~List(); // Description: Inserts a new element into a list // Pre: Define it! // Post: Define it! // In the ADT: insert(in: Element e, in: Integer position) void insert(element e, int position); // Description: Removes an element from a list // Pre: Define it! // Post: Define it! // In the ADT: remove(in: Integer position)? remove(?); // Description: Checks whether a list is empty or not // Pre: true // Post: result = true if the list is empty, false otherwise // In the ADT: isempty(out: Boolean) bool isempty() //Description: Checks whether an element is part of a // list. // Pre: Define it! // Post: result = Define it! // In the ADT: iselement(in:?, out: Boolean)? iselement(?)? size(?) //More operations? }; private: // How are we supposed to represent a linked list? What // data members do we need? Go on reading about linked // lists! But first, do exercise 1! // (Övningsuppgift 1) and read chapter 3 in Carrano.