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