Föreläsning 4 Innehåll Abstrakta datatypen lista Definition Abstrakta datatypen lista egen implementering Datastrukturen enkellänkad lista Nästlade klasser statiska nästlade klasser inre klasser Listklasser i Java Implementera abstrakta datatyperna stack och kö med vektor eller enkellänkad lista. En lista är en följd av. Det finns en före-efter-relation mellan en. Begrepp som första et i listan, efterföljaren till visst ilistan ärmeningsfulla.detfinnsalltsåettpositionsbegrepp. Definitionen innebär inte att en är sorterade på något visst sätt t.ex. i storleksordning. :a et :a et :e et 4:e et Datavetenskap (LTH) Föreläsning 4 VT 08 / 4 Datavetenskap (LTH) Föreläsning 4 VT 08 / 4 Abstrakt datatypen lista Implementering av listor Abstrakt datatyp En abstrakt modell tillsammans med de operationer man kan utföra på den. Abstrakt modell: lista Operationer på modellen: Lägga in i listan (först, sist ) Ta bort ett ur listan Undersöka om ett visst finns i listan Ta reda på ett et i listan (första, sista ) Undersöka om listan tom En vektor kan användas för att hålla reda på listans. 0 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). Datavetenskap (LTH) Föreläsning 4 VT 08 / 4 Datavetenskap (LTH) Föreläsning 4 VT 08 4 / 4
Egen implementering av listor från grunden Vektor Egen implementering av listor från grunden Enkellänkad lista size a 0 4 5 6 7 8 9 first null objekt som satts in i vektorn objekt som satts in i listan Datavetenskap (LTH) Föreläsning 4 VT 08 5 / 4 Datavetenskap (LTH) Föreläsning 4 VT 08 6 / 4 Enkellänkad lista Implementering public class SingleLinkedList<E> { private ListNode<E> first; // referens till första noden // null om listan är tom..metoder.. /* Statisk nästlad klass. Representerar en nod som innehåller ett av typ E. */ private static class ListNode<E> { private E ; // data som lagras private ListNode<E> ; // refererar till nästa nod private ListNode(E e) { = e; = null; Datavetenskap (LTH) Föreläsning 4 VT 08 7 / 4 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: statiska nästlade klasser inre klasser (eng: inner classes). Datavetenskap (LTH) Föreläsning 4 VT 08 8 / 4
Statiska 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. Datavetenskap (LTH) Föreläsning 4 VT 08 9 / 4 Att skapa objekt av nästlade klasser 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. Datavetenskap (LTH) Föreläsning 4 VT 08 0 / 4 Att skapa objekt av nästlade klasser Statiska nästlade klasser Om den nästlade klassen är statisk: 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. 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(); Datavetenskap (LTH) Föreläsning 4 VT 08 / 4 Datavetenskap (LTH) Föreläsning 4 VT 08 / 4
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. public class SingleLinkedList<E> { private ListNode<E> first; private static class ListNode<E> { private E ; // data som lagras private ListNode<E> ; // refererar till nästa nod Datavetenskap (LTH) Föreläsning 4 VT 08 / 4 Datavetenskap (LTH) Föreläsning 4 VT 08 4 / 4 Exempel på metoder i en enkellänkad lista Insättning och borttagning först i listan Länka in en ny nod innehållande et x först ilistan: public void addfirst(e x) { ListNode<E> n = new ListNode<E>(x); n. = 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.; return temp.; Datavetenskap (LTH) Föreläsning 4 VT 08 5 / 4 Traversering av en i listan Exempel: metoden tostring 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..tostring()); if (p.!= null) { sb.append(", "); p = p.; sb.append( ] ); return sb.tostring(); Datavetenskap (LTH) Föreläsning 4 VT 08 6 / 4
Traversering av en i listan Mönster Diskutera ListNode<E> p = first; while (p!= null) { p = p.; 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? Datavetenskap (LTH) Föreläsning 4 VT 08 7 / 4 Datavetenskap (LTH) Föreläsning 4 VT 08 8 / 4 Exempel på metoder i en enkellänkad lista Insättning sist i listan Söka upp sista noden i listan Mönster Länka in en ny nod innehållande et x sist ilistan: public void addlast(e x) { ListNode<E> n = new ListNode<E>(x); if (first == null) { first = n; else { ListNode<E> p = first; while(p.!= null) { p = p.; p. = n; if (first == null) { else { ListNode<E> p = first; while (p.!= null) { p = p.; // Här refererar p till sista noden Datavetenskap (LTH) Föreläsning 4 VT 08 9 / 4 Datavetenskap (LTH) Föreläsning 4 VT 08 0 / 4
Exempel på metoder i en enkellänkad lista Borttagning sist i listan Diskutera public E removelast() { if (first == null) { // tom lista throw new NoSuchElementException(); if (first. == null) { // ett ListNode<E> temp = first; first = null; return temp.; ListNode<E> p = first; // minst två ListNode<E> pre = null; while (p.!= null) { pre = p; p = p.; pre. = null; return p.; Datavetenskap (LTH) Föreläsning 4 VT 08 / 4 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 Man kan förenkla implementeringar av vissa operationer ytterligare genom att ha ett speciellt ("huvud") i början av listan. Två av metoderna vi implementerat, add och removelast, är långsammare än motsvarande metoder för att sätta in och ta bort i början av listan. Både add och removelast innehåller en loop. Ge förslag på hur man kan implementera listklassen så att dessa loopar kan tas bort. Datavetenskap (LTH) Föreläsning 4 VT 08 / 4 Traversering av listor iteratorer Användare av en listklass behöver möjlighet att gå igenom en 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> { Datavetenskap (LTH) Föreläsning 4 VT 08 / 4 Datavetenskap (LTH) Föreläsning 4 VT 08 4 / 4
Interfacet Iterator metoder Iteratorklass Inre klassen MyListIterator /** Returns true if the iteration has more s. */ boolean hasnext(); /** Returns the in the iteration. */ E (); /** Removes from the underlying collection the returned by the iterator (optional). */ default void remove(); Metoder deklarerade default är redan implementerade. Default-metoden remove genererar UnsupportedOperationException. private class MyListIterator implements Iterator<E> { private ListNode<E> pos; private MyListIterator() {pos = first; public boolean hasnext() {return pos!= null; public E () { if (hasnext()) { ListNode<E> temp = pos; pos = pos.; return temp.; else { throw new NoSuchElementException(); Datavetenskap (LTH) Föreläsning 4 VT 08 5 / 4 Datavetenskap (LTH) Föreläsning 4 VT 08 6 / 4 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.(); Eftersom vår klass SingleLinkedList implementerar interfacet Iterable kan vi också använda foreach -satsen: for (String s : list) { Datavetenskap (LTH) Föreläsning 4 VT 08 7 / 4 Datavetenskap (LTH) Föreläsning 4 VT 08 8 / 4
Listklasser i java.util Det finns två konkreta generiska klasser i Javas API för listhantering. Båda implementerar interfacet List. <<Interface>> Iterable Diskutera Nu när vi implementerat en egen listklass kan vi jämföra olika listimplementeringar: ArrayList implementeras med hjälp av en vektor: ArrayList<E>, som implementerats med vektor LinkedList<E>, som implementerats med en dubbel-länkad cirkulär struktur <<Interface>> Collection <<Interface>> List 0 4 5 6 7 8 9 Inuti LinkedList används en cirkulär, dubbellänkad struktur: ArrayList LinkedList Fördelar, nackdelar? Datavetenskap (LTH) Föreläsning 4 VT 08 9 / 4 Datavetenskap (LTH) Föreläsning 4 VT 08 0 / 4 ArrayList vs LinkedList Implementera abstrakta datatyperna stack och FIFO-kö ArrayList De indexerade metoderna get(int idx) och set(int idx, E ) är effektiva i ArrayList. Däremot är insättningar och borttagningar (utom sist i listan) långsamma eftersom måste flyttas. LinkedList De indexerade metoderna är långsamma eftersom listan måste stegas igenom tills önskat 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. Vi har tidigare sett ett exempel hur man kan skriva en stack-klass genom att internt använda LinkedList eller ArrayDeque. Fördelen är att det är enkelt och koden blir kort. Men det bli dubbla metodanrop. Om vi anropar push i vår stackklass, så anropas också push i LinkedList, En onödigt komplicerad datastruktur används. 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. Istället kan man använda en vektor eller en enkellänkad lista för att implementera de abstrakta datatyperna stack och FIFO-kö. Datavetenskap (LTH) Föreläsning 4 VT 08 / 4 Datavetenskap (LTH) Föreläsning 4 VT 08 / 4
Diskutera Implementering av stack Enkellänkad datastruktur Hur kan man använda en enkellänkad lista för att implementera en stack? Hur kan man använda en vektor lista för att implementera en stack? 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 -referenser. first Datavetenskap (LTH) Föreläsning 4 VT 08 / 4 Datavetenskap (LTH) Föreläsning 4 VT 08 4 / 4 Enkellänkad implementering av stack Vektorimplementering av stack s = new MyStack<Integer>(); s.push(); s.push(); s.push(); int i = s.pop() // i får värdet first = null first first first first 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. Datavetenskap (LTH) Föreläsning 4 VT 08 5 / 4 Datavetenskap (LTH) Föreläsning 4 VT 08 6 / 4
Vektorimplementering av stack Implementering av kö Enkellänkad datastruktur s = new MyStack<Integer>(); size = 0 s.push(); s.push(); s.push() size = size = Enkellänkad datastruktur för FIFO-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 -referenser. int i = s.pop() // i får värdet size = first s.push(4); 4 size = Datavetenskap (LTH) Föreläsning 4 VT 08 7 / 4 Datavetenskap (LTH) Föreläsning 4 VT 08 8 / 4 Enkellänkad implementering av kö Vektorimplementering av kö q = new MyQueue<Integer>(); first = = null q.offer(); q.offer(); q.offer(); first first first 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) et front index för sista (yngsta) et rear antalet size Även här kan vi behöva skapa större vektor när antalet blivit för stort. int i = q.poll() // i får värdet first Datavetenskap (LTH) Föreläsning 4 VT 08 9 / 4 Datavetenskap (LTH) Föreläsning 4 VT 08 40 / 4
Vektorimplementering av kö Exempel på vad du ska kunna q = new MyQueue<Integer>(); q.offer(); q.offer(); q.offer(); q.offer(4); q.offer(5); int i = q.poll() // i får värdet q.offer(6); front = 0, rear = -, size = 0 front = 0, rear = 0, size = 4 5 front = 0, rear = 4, size = 5 4 5 front =, rear = 4, size = 4 6 4 5 front =, rear = 0, size = 5 Implementera en lista 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. Med hjälp av dokumentation använda klasser och interface från Java Collections Framework: List, Queue, Deque, ArrayList, LinkedList, ArrayDeque, Iterator, ListIterator och Iterable Implementera en lista, stack eller kö effektivt med hjälp av vektor respektive länkade struktur. Datavetenskap (LTH) Föreläsning 4 VT 08 4 / 4 Datavetenskap (LTH) Föreläsning 4 VT 08 4 / 4 Datorlaboration Enkellänkad lista Implementera egna generisk klasser som beskriver en FIFO-kö. I en klass ska du delegera till klassen LinkedList. I den andra klassen ska du använda en cirkulär, enkellänkad lista för att hålla reda på en i kön. Utifrån sett ser kön ut så här: Inuti klassen är den uppbyggd så här: size Tips! Rita för att förstå vad som händer i programmet! Innehåll: kö, enkellänkad lista, iterator, testning med JUnit. Datavetenskap (LTH) Föreläsning 4 VT 08 4 / 4