Föreläsning 10 ADT:er och datastrukturer ADT:er och datastrukturer • Dessa två begrepp är kopplade till varandra men de står för olika saker. • En ADT (abstrakt datatyp) är just abstrakt och är inte kopplad till något programmeringsspråk eller till implementering. • En datastruktur är konkret och till de flesta programmeringsspråk finns en eller flera inbyggda datastrukturer. 2 ADT (abstrakt datatyp) • En ADT är en programspråksoberoende beskrivning av en mängd data och operationer på denna data för att lagra, komma åt och manipulera den. • Abstrakta datatyper är abstrakta i den meningen att det inte finns definierat hur datan och operationerna är implementerade. • Primitiva datatyper som heltal och flyttal har värde och operationer (t.ex. plus, minus, multiplikation och division). Precis som primitiva datatyper har värde och operationer har också abstrakta datatyper det. • I objektorienterade programmeringsspråk (som Java) implementeras ADT:er med klasser. 3 ADT (abstrakt datatyp) • Exempel på vanliga abstrakta datatyper är: - mängd - sekvens (lista, kö, stack) - träd (binärt sökträd, AVL-träd, B-träd) - graf • I lab 3 kom vi i kontakt med ADT:n Memory som är en beskrivning av den data och de operationer (på den datan) som behövs för en miniräknare. • Många programmeringsspråk har inbyggda implementationer av vissa ADT:er. Exempelvis finns olika list-implementationer i Java. I Java finns också olika gränssnitt för att underlätta implementerandet av ADT:er. 4 Datastruktur • En datastruktur är en samling data (sammanbundna på något sätt) med ett namn och en mängd operationer. Operationerna kan variera från datastruktur till datastruktur men inkluderar metoder för att ge åtkomst till datan. • När man implementerar en ADT kan man behöva en datastruktur. • En datastruktur kan modellera en abstrakt datatyp. • I Java finns flera datastrukturer som modellerar en lista: - Vector (bygger på en array) - ArrayList (bygger på en array) - DefaultListModel (bygger på en Vector) - LinkedList (bygger på länkade noder) 5 ADT:n Lista • Datat i en lista utgörs av en ordnad sekvens av element. • Operationerna utgörs exempelvis av: - insättning av element (på godtycklig plats) - borttagning av element (på godtycklig plats) - borttagning av specifikt element - sökning av element - beräkning av listans storlek - kontroll av huruvida listan är tom eller inte - platsbestämning av ett visst element - utplockning av element på en viss plats 6 Klassen Vector • Klassen Vector är en datastruktur som modellerar en lista. • Klassen Vector är en generisk klass, vilket innebär att man med den kan skapa alla typer av listor (exempelvis heltalslistor, ellipslistor, etc.). När man skapar listan (med new) talar man om vad för slags element listan ska innehålla. Vector <Ellipse> _ellipseList; _ellipseList = new Vector <Ellipse>(); • Klassen Vector finns i paketet java.util 7 Några metoder i klassen Vector Metod Beskrivning Skapar en tom lista av element Vector <E>() av typ E void addElement(E element) Lägger “element” i slutet av listan Returnerar elementet på plats E elementAt(int index) index i listan Returnerar sant om listan är tom, boolean isEmpty() annars falskt boolean Tar bort första förekomst av remove(E element) “element” i listan Tar bort elementet på plats index E remove(int index) i listan int size() Returnerar antalet element i listan 8 import java.util.*; Att använda generiska klasser public class DataStructures { private Vector <Integer> _vector; } public DataStructures() { _vector = new Vector<Integer>(); } public void test() { int sum = 0; for (int i = 0; i < 5; i++) _vector.addElement(new Integer(i)); for (int i = 0; i < _vector.size(); i++) sum += _vector.elementAt(i).intValue(); System.out.println(“Summan = “ + sum); } public static void main(String [] args) { DataStructures ds = new DataStructures(); ds.test(); } 9 Att göra generiska klasser public class Holder <E> { private E _element; public Holder() { super(); } public E getElement() { return _element; } } public void setElement(E aElement) { _element = aElement; } 10 Jämförelse av List-klasser Klass Vector ArrayList Underliggande struktur Array Generisk Ja Ja Array Nej DefaultListModel Vector (lista av Object) LinkedList Länkade noder Ja Kommentarer: Vector och ArrayList nästan identiska klasser. Vad skiljer dessa från en array? (Se tabell 13.1) Vad skiljer en array från länkade noder? Vad innebär det att DefaultListModel är en lista av Object? 11 Jämför array med klasserna Vector och ArrayList Fördelar Nackdelar Array Mer effektiv Storlek måste anges Vector & ArrayList Växer, krymper Ökad läsbarhet Mindre effektiv För fler skillnader, se kursboken tabell 13.1. 12 Jämför array med länkade noder Array (med 5 element): m i n n e t + effektiv vid hämtning - ineffektiv vid insättning och borttagning Länkad lista (med 5 element): + effektiv vid insättning och borttagning - ineffektiv vid hämtning 13 Jämför generiska List-klasser med List-klasser med Object • Antag att vi har en klass Person med konstruktorn public Person(String aName, int anAge) och att vi vill skapa en lista med personer. • Alternativ 1: Använd en generisk klass som Vector: Vector<Person> _list = new Vector<Person>(); _list.addElement(new Person(“Siv”, 25)); .... Person p = _list.elementAt(0); • Alternativ 2: Använd en klass med Object (DefaultListModel) och polymorfism: DefaultListModel _list = new DefaultListModel(); _list.addElement(new Person(“Erik”, 16)); .... Person p = (Person)_list.elementAt(0); 14 Designmönstret Iterator Pattern • Med Iterator-mönstret kan en klient komma åt innehållet i en datastruktur utan att känna till detaljerna om datastrukturens uppbyggnad. • I Java implementeras Iterator-mönstret som gränssnittet Iterator med följande metoder: Metod boolean hasNext() E next() void remove() Beskrivning Returnerar sant om fler element finns att besöka Returnerar nästa element att besöka Tar bort det senast returnerade elementet 15 Designmönstret Iterator Pattern • Ett exempel på hur man använder Iterator-mönstret. Antag att vi vill göra en metod för att summera heltalen i en Vector<Integer>-lista: public int sum(Vector<Integer> vek) { int sum = 0; Iterator<Integer> iterator = vek.iterator(); while (iterator.hasNext()) { sum += iterator.next().intValue(); } } return sum; Jämför med metoderna till Scanner-klassen, som implementerar Iterator<String>. 16 Syftet med Lab 4 är att: • ge övning i att använda abstrakta datatyper (ADT), • ge övning i att använda olika datastrukturer, • ge övning i att använda kontrakt (för- och eftervillkor), • ge övning i att skriva kommentarer i kod, och • ge fortsatt övning i objektorienterad programmering och i att göra grafiska användargränssnitt. 17 Laborationsuppgift Gör ett grafiskt användargränssnitt för en affär med följande funktioner: • Användaren ska kunna lägga till en person i affären med namn och ålder. • Användaren ska kunna flytta en av personerna i affären till en av de två kassaköerna. • Användaren ska kunna låta betjäna personen först i någon av kassaköerna (dvs personen lämnar kassakön och butiken). • Dessutom ska det grafiska användargränssnittet hela tiden visa personerna (med namn och ålder) som finns dels ute i butiken och dels i de båda kassaköerna. 18 Analys (substantiv i rött, verb i blått) Gör ett grafiskt användargränssnitt för en affär med följande funktioner: • Användaren ska kunna lägga till en person i affären med namn och ålder. • Användaren ska kunna flytta en av personerna i affären till en av de två kassaköerna. • Användaren ska kunna låta betjäna personen först i någon av kassaköerna (dvs personen lämnar kassakön och butiken). • Dessutom ska det grafiska användargränssnittet hela tiden visa personerna (med namn och ålder) som finns dels ute i butiken och dels i de båda kassaköerna. 19 Analys • Analysen ger att vi bör ha klasser för (substantiven) - Affär - Kö (kassakö) - Person • Klassen Person bör ha attribut för - Namn - Ålder • Klassen Affär bör ha komponenter - Kö (2 stycken) och följande metoder (verben) - lägga till (person) - flytta (person till någon av de två köerna) - låta betjäna (person först i kön försvinner) • Klasserna Affär och Kö måste ha en lista för att spara personer. 20 Design • Gör ADT:er. Försök att göra ADT:n Kö, dvs tänk igenom vilka egenskaper och metoder en kö ska ha. Gör kontrakt till metoderna. • Gör en skiss på layouten och tänk igenom vilka komponenter som behövs. Förutom knappar (JButton), etiketter (JLabel), fönster (JFrame) och paneler (JPanel) behöver vi till denna applikation textfält (JTextField) där användaren kan skriva in personernas namn respektive ålder samt fält där personerna i affären och i köerna visas. Använd swing-komponenten JList för dessa fält (klickbar). När man skapar ett JList-objekt ska man samtidigt skicka med en lista (DefaultListModel). Låt därför listorna som finns i klasserna Affär och Kö vara av typen DefaultListModel. 21 Design • Skissa på ett UML-diagram. Ett första utkast kan se ut så här: Affär 1 - _lista: DefaultListModel - _kassa1: Kö - _kassa2: Kö + Affär() + läggaTill(?): ? + flytta(?): ? + betjäna(?): ? + getLista(): DefaultListModel ....... 2 Kö - _lista: DefaultListModel jmf. med ADT:n Person - _namn: ? - _ålder: ? ? 22 Implementering • Utgå från klassdiagrammet. • Det är bättre att göra många och korta metoder än få och långa. • De tre klasserna för Affär, Kö och Person måste finnas med (namnen på dem kan dock bytas ut). • De tre klasserna ovan måste vara ordentligt dokumenterade i koden med beskrivning och kontrakt för varje metod. • Använd swing-komponenten JList för att visa personerna i GUI:t (se Java API). • Använd datastrukturen DefaultListModel för listorna i Affär och Kö. 23 Testning • Testa applikationen noga för alla möjliga indata (även de som är “felaktiga”). Tänk på vettiga felutskrifter i GUI:t. • Inga undantag får kastas utan att fångas upp. 24