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). I 2:a upplagan: 2.1 2.3, 2.5 2.7, 2.9-2.10, 3.1 3.3, 4.1 4.4 PFK (Föreläsning 3-4) HT 2016 1 / 76
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 PFK (Föreläsning 3-4) HT 2016 2 / 76
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) En klass är en implementering av en ADT (ex. ArrayList). PFK (Föreläsning 3-4) HT 2016 3 / 76
Abstrakta modellen lista Verkliga problem Kö av människor Bokregister Schema Inköpslista Abstrakt modell Lista PFK (Föreläsning 3-4) HT 2016 4 / 76
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). PFK (Föreläsning 3-4) HT 2016 5 / 76
Listklasser i java.util Det finns två konkreta generiska klasser i Javas API för listhantering. Båda implementerar interfacet List. <<Interface>> Iterable ArrayList<E>, som implementerats med vektor LinkedList<E>, som implementerats med en dubbel-länkad cirkulär struktur <<Interface>> Collection <<Interface>> List ArrayList LinkedList PFK (Föreläsning 3-4) HT 2016 6 / 76
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()); PFK (Föreläsning 3-4) HT 2016 7 / 76
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; PFK (Föreläsning 3-4) HT 2016 8 / 76
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. PFK (Föreläsning 3-4) HT 2016 9 / 76
Interfacet ListIterator <<Interface>> Iterator <<Interface>> ListIterator public interface ListIterator<E> extends Iterator<E> { boolean hasprevious(); E previous(); void add(e x);... PFK (Föreläsning 3-4) HT 2016 10 / 76
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))); PFK (Föreläsning 3-4) HT 2016 11 / 76
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; PFK (Föreläsning 3-4) HT 2016 12 / 76
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. PFK (Föreläsning 3-4) HT 2016 13 / 76
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)); PFK (Föreläsning 3-4) HT 2016 14 / 76
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). PFK (Föreläsning 3-4) HT 2016 15 / 76
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. PFK (Föreläsning 3-4) HT 2016 16 / 76
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. PFK (Föreläsning 3-4) HT 2016 17 / 76
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. PFK (Föreläsning 3-4) HT 2016 18 / 76
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. PFK (Föreläsning 3-4) HT 2016 19 / 76
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 PFK (Föreläsning 3-4) HT 2016 20 / 76
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); PFK (Föreläsning 3-4) HT 2016 21 / 76
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. PFK (Föreläsning 3-4) HT 2016 22 / 76
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; PFK (Föreläsning 3-4) HT 2016 23 / 76
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. PFK (Föreläsning 3-4) HT 2016 24 / 76
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. PFK (Föreläsning 3-4) HT 2016 25 / 76
Egen implementering av listor från grunden Vektor a 0 1 2 3 4 5 6 7 8 9 size 3 objekt som satts in i vektorn PFK (Föreläsning 3-4) HT 2016 26 / 76
Egen implementering av listor från grunden Enkellänkad lista first next element next element next element null objekt som satts in i listan PFK (Föreläsning 3-4) HT 2016 27 / 76
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; PFK (Föreläsning 3-4) HT 2016 28 / 76
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). PFK (Föreläsning 3-4) HT 2016 29 / 76
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. PFK (Föreläsning 3-4) HT 2016 30 / 76
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 omgivande klassen som skapade objektet av den inre klassen. PFK (Föreläsning 3-4) HT 2016 31 / 76
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. PFK (Föreläsning 3-4) HT 2016 32 / 76
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(...); PFK (Föreläsning 3-4) HT 2016 33 / 76
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(); PFK (Föreläsning 3-4) HT 2016 34 / 76
Å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... PFK (Föreläsning 3-4) HT 2016 35 / 76
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; PFK (Föreläsning 3-4) HT 2016 36 / 76
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(); PFK (Föreläsning 3-4) HT 2016 37 / 76
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? PFK (Föreläsning 3-4) HT 2016 38 / 76
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; PFK (Föreläsning 3-4) HT 2016 39 / 76
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; PFK (Föreläsning 3-4) HT 2016 40 / 76
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. PFK (Föreläsning 3-4) HT 2016 41 / 76
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. PFK (Föreläsning 3-4) HT 2016 42 / 76
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> {... PFK (Föreläsning 3-4) HT 2016 43 / 76
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. PFK (Föreläsning 3-4) HT 2016 44 / 76
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();... PFK (Föreläsning 3-4) HT 2016 45 / 76
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> {...... PFK (Föreläsning 3-4) HT 2016 46 / 76
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) {... PFK (Föreläsning 3-4) HT 2016 47 / 76
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? PFK (Föreläsning 3-4) HT 2016 48 / 76
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. PFK (Föreläsning 3-4) HT 2016 49 / 76
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 PFK (Föreläsning 3-4) HT 2016 50 / 76
ADT Stack En stack beskrivs oftast lodrätt orienterad. Operationer sker på toppen av stacken. push pop PFK (Föreläsning 3-4) HT 2016 51 / 76
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. PFK (Föreläsning 3-4) HT 2016 52 / 76
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? PFK (Föreläsning 3-4) HT 2016 53 / 76
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(); PFK (Föreläsning 3-4) HT 2016 54 / 76
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() PFK (Föreläsning 3-4) HT 2016 55 / 76
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. PFK (Föreläsning 3-4) HT 2016 56 / 76
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. PFK (Föreläsning 3-4) HT 2016 57 / 76
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. PFK (Föreläsning 3-4) HT 2016 58 / 76
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? PFK (Föreläsning 3-4) HT 2016 59 / 76
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. PFK (Föreläsning 3-4) HT 2016 60 / 76
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();... PFK (Föreläsning 3-4) HT 2016 61 / 76
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. PFK (Föreläsning 3-4) HT 2016 62 / 76
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. PFK (Föreläsning 3-4) HT 2016 63 / 76
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 PFK (Föreläsning 3-4) HT 2016 64 / 76
Enkellänkad implementering av stack s = new MyStack<Integer>(); first = null s.push(1); first 1 s.push(2); first 2 1 s.push(3); first 3 2 1 int i = s.pop() // i får värdet 3 first 2 1 PFK (Föreläsning 3-4) HT 2016 65 / 76
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. PFK (Föreläsning 3-4) HT 2016 66 / 76
Vektorimplementering av stack s = new MyStack<Integer>(); size = 0 s.push(1); 1 size = 1 s.push(2); s.push(3) 1 2 3 size = 3 int i = s.pop() // i får värdet 3 1 2 3 size = 2 s.push(4); 1 2 4 size = 3 PFK (Föreläsning 3-4) HT 2016 67 / 76
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 poll offer PFK (Föreläsning 3-4) HT 2016 68 / 76
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(); PFK (Föreläsning 3-4) HT 2016 69 / 76
Interface Queue i java.util <<Interface>> Iterable <<Interface>> Collection <<Interface>> Queue ArrayDequeu LinkedList 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() PFK (Föreläsning 3-4) HT 2016 70 / 76
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 PFK (Föreläsning 3-4) HT 2016 71 / 76
Enkellänkad implementering av kö q = new MyQueue<Integer>(); first = last = null q.offer(1); first 1 last q.offer(2); first 2 1 last q.offer(3); first 1 2 3 last int i = q.poll() // i får värdet 1 first 2 3 last PFK (Föreläsning 3-4) HT 2016 72 / 76
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. PFK (Föreläsning 3-4) HT 2016 73 / 76
Vektorimplementering av kö q = new MyQueue<Integer>(); front = 0, rear = -1, size = 0 q.offer(1); 1 front = 0, rear = 0, size = 1 q.offer(2); q.offer(3); q.offer(4); q.offer(5); 1 2 3 4 5 front = 0, rear = 4, size = 5 int i = q.poll() // i får värdet 1 1 2 3 4 5 front = 1, rear = 4, size = 4 q.offer(6); 6 2 3 4 5 front = 1, rear = 0, size = 5 PFK (Föreläsning 3-4) HT 2016 74 / 76
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 lista så att man kan använda de klasser som finns i biblioteket. PFK (Föreläsning 3-4) HT 2016 75 / 76
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: 1 2 3 Inuti klassen är den uppbyggd så här: next element next element next element 1 2 3 last size 3 Tips! Rita för att förstå vad som händer i programmet! Innehåll: kö, enkellänkad lista, iterator, testning med JUnit. PFK (Föreläsning 3-4) HT 2016 76 / 76