Föreläsning 3-4
Innehåll
Listor, stackar, köer
Abstrakta datatypen lista
listklasser i Java, egen implementering
Datastrukturen enkellänkad lista
Jämföra element – metoden equals, interfacet Comparable Abstrakta datatyperna stack och kö
Undervisningsmoment:
föreläsning 3-4, övningsuppgifter 4-5 och laboration 2 Avsnitt i läroboken:
2.2–2.4, 2.5–2.8, 2.10, 4.1–4.3, 4.5–4.8. Läs gärna även kap 3 (om testning).
Abstrakta datatypen lista
Definition
En lista är en följd av element.
Det finns en före-efter-relation mellan elementen.
Begrepp som ”första elementet i listan”, ”efterföljaren till visst element i listan” är meningsfulla. Det finns alltså ett positionsbegrepp.
Definitionen innebär inte att elementen är sorterade på något visst sätt t.ex. i storleksordning.
1:a elementet 2:a elementet 3:e elementet 4:e elementet
Abstrakt datatypen lista
Abstrakt datatyp
En abstrakt modell tillsammans med de operationer man kan utföra på den.
Abstrakt modell: lista
Operationer på modellen:
Lägga in element i listan (först, sist ...) Ta bort ett element ur listan
Undersöka om ett visst element finns i listan
Ta reda på ett elementet i listan (första, sista ...) Undersöka om listan tom
...
En ADT kan beskrivas av en specifikation av en klass eller av ett interface (t.ex. List i paketet java.util)
Abstrakta modellen lista
Abstrakt modell Verkliga problem
Bokregister
Kö av människor
Lista
Schema
Inköpslista
Implementering av listor
En vektor kan användas för att hålla reda på listans element.
0 1 2 3
Ett annat sätt är att utnyttja länkad datastruktur.
I en länkad struktur består listan av noder som har en referens till efterföljaren (och ev. till föregångaren).
Listklasser i java.util
Det finns två konkreta generiska klasser i Javas API för listhantering. Båda implementerar interfacet List.
ArrayList<E>, som implementerats med vektor
LinkedList<E>, som implementerats med en dubbel-länkad cirkulär struktur
<<Interface>>
Collection
ArrayList
<<Interface>>
List
LinkedList
<<Interface>>
Iterable
Användning av ArrayList/LinkedList
Traversering
List<Person> list = new ArrayList<Person>();
list.add(new Person("Kili", 1));
list.add(new Person("Balin", 2));
list.add(new Person("Dori", 3));
// skriv ut alla personerna for (Person p: list) {
System.out.println(p);
}
// samma sak med explicit iterator
Iterator<Person> itr = list.iterator();
while (itr.hasNext()) {
System.out.println(itr.next());
}
Skugga toString
Inuti println(p) anropas metoden toString på p. Metoden toString finns i superklassen Object.
Skugga (omdefiniera) metoden toString för att bestämma hur utskriften av objektet ska se ut:
public class Person { private String name;
private int id;
public Person (String name, int id) { this.name = name;
this.id = id;
}
public String toString() { return name + " " + id;
} }
Interfacet ListIterator
Interfacet List i java.util föreskriver att det för listor även ska finnas metoder:
/** Returnerar en listiterator som startar i pos i. */
public ListIterator listIterator(int i);
/** Returnerar en listiterator som startar i pos 0. */
public ListIterator listIterator();
ListIterator<E> är ett interface som ärver Iterator<E> och där man lagt till metoder för att röra sig även bakåt i listor samt för att sätta in element.
Interfacet ListIterator
<<Interface>>
Iterator
<<Interface>>
ListIterator
public interface ListIterator<E> extends Iterator<E> { boolean hasPrevious();
E previous();
void add(E x);
...
}
Diskutera
Följande klass beskriver en person:
public class Person {
private String name;
private int;
public Person (String name, int id) { this.name = name;
this.id = id;
} }
Vad skrivs ut när följande rader exekveras? Förklara varför?
ArrayList<Person> list = new ArrayList<Person>();
list.add(new Person("Fili", 1));
list.add(new Person("Balin", 2));
System.out.println(list.contains(new Person("Balin", 2)));
Jämföra likhet
Metoden equals
Inuti ArrayList används metoden equals för att jämföra om två objekt är lika:
if (p1.equals(p2)) {...}
Metoden equals finns i superklassen Object. Den returnerar true om och endast om de jämförda objekten är identiska. Den testar referenslikhet och fungerar alltså som == i Java.
Om vi istället vill att innehållet inuti objekten ska jämföras (här id-numren) måste vi skugga equals klassen Person.
Skiss, ej färdig equals-metod:
public boolean equals(Object obj) { return id == ((Person) obj).id;
}
Jämföra likhet
Skillnad Java - Scala
I Java är == en operator som jämför referenser. Exempel: p1 == p2 ger true om p1 och p2 refererar till samma objekt.
I klassen Object finns metoden equals som fungerar som ==. Den måste skuggas om man vill få ett annat beteende i egna klasser.
I Scala är == en metod som anropar equals. Skugga equals om annat beteende önskas.
Metoden eq testar referenslikhet och p1.eq(p2) ger true om p1 och p2 refererar till samma objekt.
Användning av ArrayList/LinkedList
Söka efter objekt i en lista
List<Person> list = new ArrayList<Person>();
list.add(new Person("Kili", 1));
list.add(new Person("Balin", 2));
list.add(new Person("Dori", 3));
// sök efter platsen för elementet med id-nummer 2 int index = list.indexOf(new Person(null, 2));
// tag reda på om det finns ett element med id-nummer 2 i listan boolean found = list.contains(new Person(null, 2));
// tag bort elementet med id-nummer 2 ur listan
boolean removed = list.remove(new Person(null, 2));
Skugga equals – att tänka på
Parametern till equals måste vara av typ Object, annars blir det inte skuggning och den ursprungliga metoden i klassen Object kommer att användas.
De attribut som används i jämförelsen inuti equals bör inte gå att ändra. Deklarera dem final:
public class Person { private String name;
private final int id;
...
Annars kan det bli svårt att hitta objektet när det satts in i en lista eller annan samling.
När man skuggar equals bör man också skugga metoden hashCode.
Metoderna equals och hashCode används när objekt sätts in i en hashtabell. (Behandlas senare i kursen).
Skugga equals
Specifikation
public boolean equals(Object obj);
Ur equals specifikation:
x.equals(x) ska returnera true (reflexivitet).
Om x.equals(y) returnerar true så ska y.equals(x) returnera true (symmetri).
Om x.equals(y) returnerar true och y.equals(z) returnerar true så ska x.equals(z) returnera true (transitivitet).
Upprepade anrop av x.equals(y) ska ge samma resultat (konsistens).
x.equals(null) ska returnera false.
Omdefiniera equals – med instanceof
public boolean equals(Object obj) { if (obj instanceof Person) {
return idNbr == ((Person) obj).idNbr;
} else {
return false;
} }
Observera att parametern till equals måste vara av typ Object,
annars blir det inte skuggning. Därför måste också typomvandling till Person ske när man ska använda obj:s idNbr.
Uttrycket obj instanceof Person returnerar true om obj:s typ är Person eller någon subklass till Person.
Uttrycket obj instanceof Person returnerar false om obj har värdet null.
Skugga (skugga) equals – med instanceof
Fördelar och nackdelar
Denna lösningen tillåter att subklasser ärver equals-metoden.
Man kan därför använda equals i en arvshieariki och jämföra
”subklassobjekt” och ”superklassobjekt”.
Kan leda till att equals inte uppfyller kraven i specifikationen om man skuggar equals i subklassen.
Därför är det lämpligt att deklarera metoden equals final:
public final boolean equals(Object obj) { ...
Nu kan inte equals skuggas i någon subklass till Person.
Detta undviks om man bara tillåter jämförelser mellan objekt av samma typ. Se nästa bild.
Skugga equals – med getClass
public boolean equals(Object obj) { if (obj == this) {
return true;
}
if (obj == null) { return false;
}
if (this.getClass() != obj.getClass()) { return false;
}
return id == ((Person) obj).id;
}
Metoden getClass returnerar typen för det objekt obj refererar till under exekveringen.
Bara metoder av exakt samma klass kan anses vara lika.
Skugga equals – med extra metod canEqual
Ibland blir lösningen på förra bilden för sträng. Det kan man lösa genom att lägga till en extra metod i klassen:
public boolean equals(Object obj) { if (obj instanceof Person) {
Person other = (Person) obj;
return other.canEqual(this) && this.id == other.id;
} else {
return false;
} }
public boolean canEqual(Object other) { return (other instanceof Person);
}
Bägge metoderna ska skuggas i subklasser. För detaljer läs mer här:
www.artima.com/lejava/articles/equality.html
Diskutera
Sortera objekt
Klassen Person beskriver en person. Vad händer när följande rader exekveras? Förklara varför?
Person[] persons = new Person[4];
persons[0] = new Person("Kili", 1);
persons[1] = new Person("Balin", 2);
persons[2] = new Person("Dori", 4);
persons[3] = new Person("Fili", 3);
Arrays.sort(persons);
for(Person p : persons) { System.out.println(p);
}
Interfacet Comparable
Specifikation
I Java finns ett generiskt interface, Comparable<T>:
public interface Comparable<T> { /**
* Compares this object with the specified object for order.
* Returns a negative integer, zero, or a positive integer as
* this object is less than, equal to, or greater than the
* specified object.
*/
public int compareTo(T x);
}
Objekt av klasser som implementerar detta interface går att jämföra med varandra och kan t.ex. sorteras.
Inuti metoden sort används Comparable som typ för de element som ska sorteras.
Implementering av interfacet Comparable
Exempel
public class Person implements Comparable<Person> { private String name;
private int id;
...
public int compareTo(Person obj) {
return Integer.compare(id, obj.id); } public boolean equals(Object obj) {
if (obj instanceof Person) {
return compareTo((Person) obj) == 0;
} else {
return false;
} }
Jämföra likhet
Metoderna compareTo och equals
Interfacet Comparable innehåller bara metoden compareTo.
Men för klasser som implementerar interfacet Comparable finns det två sätt att jämföra avseende likhet:
Person p1 = ...;
Person p2 = ;...
if (p1.compareTo(p2) == 0) {...}
if (p1.equals(p2)) {...}
Båda sätten att jämföra bör ge konsistenta resultat.
Därför bör metoden equals skuggas i klasser som implementerar Comparable.
Typparametrar med begränsningar
Ibland behöver man ange begränsning på typparmetern:
public class ASortedCollection<E extends Comparable<E>>
<E extends T> betyder:
E måste vara subklass till T om T är en klass. Det är också tillåtet att E
= T.
E måste implementera interfacet T om T är ett interface.
I exemplet ovan anger vi alltså att E måste vara en typ som
implementerar interfacet Comparable<E>. Vi kan därmed använda metoden compareTo på objekt av typen E i implementeringen av ASortedCollection.
Egen implementering av listor från grunden
Vektor
objekt som satts in i vektorn
0 1 2 3
a
4 5 6 7
3 size
8 9
Egen implementering av listor från grunden
Enkellänkad lista
first next null
element
objekt som satts in i listan next
element next
element
Enkellänkad lista
Implementering
public class SingleLinkedList<E> {
private ListNode<E> first; // referens till första noden // null om listan är tom
..metoder..
/* Statiskt nästlad klass. Representerar en nod som innehåller ett element av typ E. */
private static class ListNode<E> {
private E element; // data som lagras
private ListNode<E> next; // refererar till nästa nod private ListNode(E e) {
element = e;
next = null;
} }
}
Nästlade klasser i Java
Klasser kan deklareras inuti andra klasser (nästlade klasser).
Används oftast när den nästlade klassen bara är meningsfull för den omgivande klassen.
Användare behöver oftast inte känna till existensen av den nästlade klassen.
En nästlad klass kan deklareras private om den bara ska användas i den omgivande klassen. Även konstruktorn kan då vara private.
I den omgivande klassen har man tillgång till allt i den nästlade klassen (även det som är private).
Det finns två typer av nästlade klasser:
statiskt nästlade klasser
inre klasser (eng: inner classes).
Statiskt nästlade klasser
public class OuterClass { ...
public void p() {
NestedClass x = new NestedClass();
...
}
private static class NestedClass { private NestedClass() {...}
...
} }
En statisk nästlad klass kan bara komma åt statiska attribut och statiska metoder i den omgivande klassen.
Inre klasser
public class OuterClass { private int i;
public void p() {
InnerClass x = new InnerClass();
...
}
private class InnerClass {
private InnerClass() {...}
private void q() {
int b = i; ...; // Här används i från OuterClass!
} }
}
Ett objekt av en inre klass kan komma åt allt i det objekt av den
Att skapa objekt av nästlade klasser
Görs oftast bara i den omgivande klassen.
Då blir det samma syntax som vanligt.
Exempel finns på föregående bilder.
Man kan skapa objekt av nästlade klasser även utanför den omgivande klassen.
Kräver dock att den nästlade klassen och dess konstruktor är public.
Detaljer på nästa bild.
Att skapa objekt av nästlade klasser
Statiska nästlade klasser
Om den nästlade klassen är statisk:
public class OuterClass { ...
public static class NestedClass { public NestedClass() {...}
...
} }
så skapas en instans av den nästlade klassen med följande syntax:
OuterClass.NestedClass x = new OuterClass.NestedClass(...);
Att skapa objekt av nästlade klasser
Inre klasser
Om den nästlade klassen är en inre klass:
public class OuterClass { ...
public class InnerClass {
public InnerClass(...) {...}
...
} }
så kan instanser av den inre klassen bara skapas genom ett objekt av den yttre klassen:
OuterClass a = new OuterClass();
OuterClass.InnerClass b = a.new InnerClass();
Åter till implementeringen av listor ...
På följande bilder visas implementeringar av några metoder i klassen SingeLinkedList. (Ytterligare exempel finns i övningsuppgifter 4.)
public class SingleLinkedList<E> { private ListNode<E> first;
...
private static class ListNode<E> {
private E element; // data som lagras
private ListNode<E> next; // refererar till nästa nod ...
} }
Exempel på metoder i en enkellänkad lista
Insättning och borttagning först i listan
Länka in en ny nod innehållande elementet x först i listan:
public void addFirst(E x) {
ListNode<E> n = new ListNode<E>(x);
n.next = first;
first = n;
}
Tag bort första noden i listan, returnera dess innehåll:
public E removeFirst() { if (first == null) {
throw new NoSuchElementException();
}
ListNode<E> temp = first;
first = first.next;
return temp.element;
}
Exempel på metoder i en enkellänkad lista
Traversering av elementen i listan
Returnera en sträng som representerar listan:
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append(’[’);
ListNode<E> p = first;
while (p != null) {
sb.append(p.element.toString());
if (p.next != null) { sb.append(", ");
}
p = p.next;
}
sb.append(’]’);
return sb.toString();
}
Diskutera
Antag att vi ska skriva metoder addLast och removeLast för att sätta in och ta bort sist listan.
Hur ska vi lösa de problemen?
Vilka specialfall finns?
Exempel på metoder i en enkellänkad lista
Insättning sist i listan
Länka in en ny nod innehållande elementet x sist i listan:
public void addLast(E x) {
ListNode<E> n = new ListNode<E>(x);
if (first == null) { first = n;
} else {
ListNode<E> p = first;
while(p.next != null) { p = p.next;
}
p.next = n;
} }
Exempel på metoder i en enkellänkad lista
Borttagning sist i listan
public E removeLast() {
if (first == null) { // tom lista throw new NoSuchElementException();
}
if (first.next == null) { // ett element ListNode<E> temp = first;
first = null;
return temp.element;
}
ListNode<E> p = first; // minst två element ListNode<E> pre = null;
while (p.next != null) { pre = p;
p = p.next;
}
pre.next = null;
return p.element;
}
Diskutera
Två av metoderna vi implementerat, addlast och removeLast, är långsammare än motsvarande metoder för att sätta in och ta bort i början av listan. Både addlast och removeLast innehåller en loop.
Ge förslag på hur man kan implementera listklassen så att dessa loopar kan tas bort.
Implementering med länkad struktur
Kommentarer
Exemplen visar att det är viktigt att tänka på specialfall.
Vissa operationer blir krångliga i den enkellänkade implementeringen.
Dessa kan förenklas om man i varje nod också har en referens till föregångaren. Detta kallas dubbellänkade listor.
first last
Man kan förenkla implementeringar av vissa operationer ytterligare genom att ha ett speciellt element ("huvud") i början av listan.
Traversering av listor – iteratorer
Användare av en listklass behöver möjlighet att gå igenom elementen i listan. Låt därför SingleLinkedList implementera interfacet Iterable:
public class SingleLinkedList<E> implements Iterable<E> { ...
Lägg till metoden
Iterator<E> iterator()
i klassen SingleLinkedList. Metoden iterator ska skapa och returnera ett iterator-objekt.
Skriv en (inre) klass som implementerar interfacet Iterator enligt mönstret:
private class MyListIterator implements Iterator<E> {...}
Interfacet Iterator
metoder
/** Returns true if the iteration has more elements. */
boolean hasNext();
/** Returns the next element in the iteration. */
E next();
/** Removes from the underlying collection the last element returned by the iterator (optional). */
default void remove();
Metoder deklarerade default är redan implementerade. Default-metoden remove genererar UnsupportedOperationException.
Iteratorklass
Inre klassen MyListIterator
private class MyListIterator implements Iterator<E> { private ListNode<E> pos;
private MyListIterator() {pos = first;}
public boolean hasNext() {return pos != null;}
public E next() { if (hasNext()) {
ListNode<E> temp = pos;
pos = pos.next;
return temp.element;
} else {
throw new NoSuchElementException();
} }
...
Metoden iterator()
Klassen SingleListIterator
public class SingleLinkedList<E> implements Iterable<E> { private ListNode<E> first;
...
public Iterator<E> iterator() { return new MyListIterator();
}
private class MyListIterator implements Iterator<E> {...}
...
}
Användning av iterator
Exempel
Nu kan vi iterera genom vår lista:
SingleLinkedList<String> list = new SingleLinkedList<String>();
// sätt in några String-objekt i listan ...
Iterator<String> itr = list.iterator();
while (itr.hasNext()) { String s = itr.next();
...
}
Eftersom vår klass SingleLinkedList implementerar interfacet Iterable kan vi också använda ”foreach”-satsen:
for (String s : list) { ...
}
Diskutera
Nu när vi implementerat en egen list-klass kan vi jämföra olika list-implementationer:
ArrayList implementeras med hjälp av en vektor:
0 1 2 3 4 5 6 7 8 9
Inuti LinkedList används en cirkulär, dubbellänkad struktur:
Fördelar, nackdelar?
ArrayList vs LinkedList
ArrayList
De indexerade metoderna get(int idx) och set(int idx, E element) är effektiva i ArrayList.
Däremot är insättningar och borttagningar (utom sist i listan) långsamma eftersom element måste flyttas.
LinkedList
De indexerade metoderna är långsamma eftersom listan måste stegas igenom tills önskat element nås.
När man väl hittat rätt plats i listan är insättningar och borttagningar snabba.
Nod-objekten kräver extra minne och hantering.
ADT Stack
Definition
En stack är en följd av element där borttagning av ett element alltid aer det element som senast satts in.
Kallas även LIFO-lista, Last In First Out
ADT Stack
En stack beskrivs oftast lodrätt orienterad.
Operationer sker på toppen av stacken.
push pop
ADT Stack i java.util
I Javas klassbibliotek har man inte infört något interface för ADT:n Stack.
Det finns en klass Stack, som ärver en annan klass Vector.
Interfacet Deque i java.util innehåller bl. a. de operationer som ska finnas för en ADT Stack:
lägg ett element överst på stacken – push(e) eller addFirst(e)
tag bort och returnera översta elementet – pop() eller removeFirst() returnera översta elementet – peek() eller peekFirst()
Exempel på klasser som implementerar interfacet Deque är ArrayDeque och LinkedList.
Diskutera
Klasserna på föregående bild innehåller för många metoder och inte bara de vanliga stack-operationerna.
Varför är det ett problem?
Hur kan man lösa detta?
Interface Stack – som det borde se ut
public interface Stack<E> {
/** Lägger x överst på stacken. */
void push(E x);
/** Tar bort och returnerar översta elementet från stacken. */
E pop();
/** Returnerar översta elementet på stacken. */
E peek();
/** Undersöker om stacken är tom. */
boolean isEmpty();
}
Exempel på användning av stack
En stack kan också användas till att
Kontrollera att parenteser matchar:
Om vänsterparentes push(parentes) Om högerparentes
pop()
Vända på elementen i en lista:
För varje element e i listan push(e)
Så länge stacken ej är tom pop()
Exempel på användning av stack
Om ett aritmetiskt heltalsuttryck är skrivet i omvänd polsk notation
(postfix notation) kan vi använda en stack för att beräkna uttryckets värde.
Operatorn placeras efter sina två operander: 10 12 –
Ex: 3 10 12 – * i postfix notation motsvarar uttrycket 3 * (10 – 12) i vanlig (infix) notation.
Fördel: alla uttryck kan skrivas utan parenteser och deras värde kan enkelt evalueras med hjälp av en stack.
Exempel på användning av stack
Algoritm
skapa en tom stack s // s = new ...
så länge uttrycket ej är slut
läs in nästa element (tal eller operator) om tal
lägg talet på stacken // push
annars (operator)
hämta de två översta talen t1 och t2 // 2 st. pop från stacken
res = resultatet av operatorn använd på t2 och t1
lägg res på stacken // push
Nu ska stacken bara innehålla ett värde – resultatet.
Exempel på användning av stack
Evaluering av uttrycket: 3 10 12 – *
Läst: inget 3 10 12 - *
12
10 10 -2
Stack: tom 3 3 3 3 -6
Om uttrycket är korrekt så ligger till sist resultatet som enda element på stacken.
Diskutera
Antag att vi behöver en stack i ett program.
Ska vi använda en färdig klass?
Eller ska vi implementera en egen klass? Hur i så fall?
Vilka för- och nackdelar har de olika alternativen?
Implementering av stack – använd färdig klass
Alternativ 1
Gör inte någon ny implementering utan använd en redan färdig klass t.ex. ArrayDeque eller LinkedList i java.util. Använd bara de
operationer som är tillåtna för stack.
+ Enkelt
– Övriga icke-stack-metoder finns tillgängliga. Risk för att anropa fel metod.
Implementering av stack - delegera till annan klass
Alternativ 2
Implementera en egen klass, men använd internt en annan klass.
Exempel:
public class Stack<E> {
private LinkedList<E> elements; // eller ArrayDeque<E>
...
public push(E x) {
elements.push(x);
}
public E peek() {
return elements.peek();
} ...
}
Delegera till annan klass, forts
Alternativ 2
+ Slipper risken att anropa fel metoder
– Många metodanrop. Om vi anropar push i Stack, så anropas också push i LinkedList, ...
– Onödigt komplicerad datastruktur som ev. är vald för att andra metoder ska bli effektiva.
Exempel: Datastrukturen i LinkedList är vald så att operationerna på listan ska bli effektiva. Det ät onödigt med dubbellänkad lista för att implementera en stack.
Implementering av stack - egen klass med enklare datastruktur
Alternativ 3
Implementera en egen klass med enklare datastruktur, t.ex. vektor eller enkellänkad lista.
+ Slipper risken att anropa fel metoder
+ Färre metodanrop än alternativ 2. T.ex. utför då push sin uppgift utan att delegera vidare till annan metod.
+ En enklare datastruktur kan ge bättre effektivitet.
– Mer kod att implementera än i alternativ 1 och 2.
Implementering av stack
Enkellänkad datastruktur
Enkellänkad datastruktur för stack:
Stacken representeras av referens till första noden.
Alla operationer kan då utföras på konstant tid, oberoende av stackens storlek.
Behöver extra utrymme för next-referenser.
first
Enkellänkad implementering av stack
first 3 2 1
first 2 1
first 1
first = null s = new MyStack<Integer>();
s.push(1);
s.push(2);
s.push(3);
first 2 1
int i = s.pop() // i får värdet 3
Vektorimplementering av stack
Vektorimplementering av stack:
Stacken representeras av vektor och index för nästa insättning (initialt 0).
Ger konstant tid för metoderna så länge vektorns storlek räcker.
Om man dubblar vektorns storlek varje gång den inte räcker till, kan man visa att metoderna fortfarande i medeltal går att utföra på
konstant tid.
Efter dubblering är bara halva utrymmet i vektorn utnyttjat.
Vektorimplementering av stack
s = new MyStack<Integer>();
s.push(1);
s.push(2); s.push(3)
int i = s.pop() // i får värdet 3
size = 0
size = 1
size = 3
size = 2
size = 3 s.push(4);
1
1
1
1
2
2
2
3
4 3
ADT Kö
Definition
En kö (FIFO-kö) är en följd av element där insättning alltid görs sist i följden.
borttagning alltid avser första elementet i följden.
First In First Out
offer poll
Interface Queue – minimalt
public interface Queue<E> {
/** Sätter in x sist i kön. */
boolean offer(E e);
/** Tar reda på första elementet i kön. */
E peek();
/** Tar reda på och tar bort första elementet i kön. */
E poll();
/** Undersöker om kön är tom. */
boolean isEmpty();
}
Interface Queue i java.util
<<Interface>>
Collection
ArrayDequeu
<<Interface>>
Queue
LinkedList
<<Interface>>
Iterable
Genererar exception vid problem
Returnerar false/null vid problem
Sätta in boolean add(E x) boolean offer(E x)
Ta bort E remove() E poll()
Ta reda på E element() E peek()
Implementering av kö
Enkellänkad datastruktur
Enkellänkad datastruktur för kö:
Kön representeras av referenser till första och sista noden.
Alla operationer kan då utföras på konstant tid, oberoende av köns längd.
Behöver extra utrymme för next-referenser.
first last
Enkellänkad implementering av kö
first 1 2 3
first 1
first = last = null q = new MyQueue<Integer>();
q.offer(1);
q.offer(2);
q.offer(3);
first 1 2
int i = q.poll() // i får värdet 1
last
last
last
first 2 3
last
Vektorimplementering av kö
Vektorimplementering av kö:
Vektorn används cirkulärt; första platsen i vektorn anses vara efterföljare till sista platsen.
Kön representeras av vektorn samt
index för första (äldsta) elementet – front index för sista (yngsta) elementet– rear antalet element – size
Även här kan vi behöva skapa större vektor när antalet element blivit för stort.
Vektorimplementering av kö
q = new MyQueue<Integer>();
q.offer(1);
q.offer(2); q.offer(3);
q.offer(4); q.offer(5);
int i = q.poll() // i får värdet 1
front = 0, rear = -1, size = 0
front = 0, rear = 0, size = 1
front = 0, rear = 4, size = 5
front = 1, rear = 4, size = 4
front = 1, rear = 0, size = 5 q.offer(6);
1
1
1
6
2
2
2
3
3
3 4 5
4 5
4 5
Listor, stackar och köer
Exempel på vad du ska kunna
Förklara vad de abstrakta datatyperna lista, stack och kö är och vilka operationer man förväntas kunna utföra på dem.
Implementera en lista, stack eller kö effektivt med hjälp av vektor respektive länkade struktur.
Förklara vad nästlade och inre klasser är för något samt kunna implementera sådana.
Använda klasser och interface från Java Collections Framework: List, Queue, Deque, ArrayList, LinkedList, ArrayDeque, Iterator,
ListIterator och Iterable
Skugga metoden equals och implementera interfacet Comparable Man ska naturligtvis inte lära sig utantill exakt vilka metoder som finns i klasser i Javas bibliotek. Det är däremot viktigt att förstå t.ex. begreppet
Datorlaboration 2
Enkellänkad lista
Implementera en egen generisk klass som beskriver en FIFO-kö.
Inuti mängdklassen ska du använda en cirkulär, enkellänkad lista för att hålla reda på elementen i kön.
Utifrån sett ser kön ut så här:
2
1 3
Inuti klassen är den uppbyggd så här:
last next
element
1
size 3 next
element
2
next element
3
Tips! Rita för att förstå vad som händer i programmet!
Innehåll: kö, enkellänkad lista, iterator, testning med JUnit.