Föreläsning 12 Länkade listor
Jämför en array med en länkad lista m in n e t Array (med 5 element): + 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 2
Nod-klass (med plats för både ett listelement och en minnesreferens) Alternativ 1 (generisk klass): public class Node<ElementType> { private ElementType _element; private Node<ElementType> _next;... Alternativ 2 (klass med Object): public class Node { private Object _element; private Node _next;... 3
Figurer För att lättare handskas med noderna i en länkad lista är det bra att rita figurer. Figur Kod enligt alternativ 2 n Node n; //deklaration n n = null; //initialisering new Node(...); n Node n = new Node(...); 4
Figurer Varje gång en nod skapas (new Node(...);) så skapas det två platser i minnet, dels för ett dataelement och dels för en minnesreferens till en nod så att man kan koppla samman flera noder till en lång kedja. dataelement minnesreferens till en nod 5
Nod-klassen (alternativ 1) public class Node<E> { private E _element; //dataelementet private Node<E> _next; //minnesreferens till en nod public Node(E element) { //konstruktor _element = element; //dataelementet initialiseras _next = null; //minnesreferensen //initialiseras till null public E getelement() { //get-metod för dataelementet return _element; public void setnext(node<e> anode) { //set-metod för minnesreferensen _next = anode; public Node<E> getnext() { //get-metod för minnesreferensen return _next; 6
Hur skapar man noder? Skapa några noder med heltalselement: Node<Integer> n1 = new Node<Integer>(new Integer(1)); Node<Integer> n2 = new Node<Integer>(new Integer(2)); Node<Integer> n3 = new Node<Integer>(new Integer(3)); n1 n2 n3 Integer-objekt med värde 1 Integer-objekt med värde 2 Integer-objekt med värde 3 7
Hur kopplar man ihop noder? Länka ihop noderna n1, n2 och n3 till en kedja: n1.setnext(n2); n2.setnext(n3); n1 n2 Integer-objekt med värde 1 Integer-objekt med värde 2 Integer-objekt med värde 3 n3 Man kan nu komma åt Integer-objektet med värde 3 på flera sätt: n3.getelement(); n1.getnext().getnext().getelement(); 8
Nodimplementation av ADT:n Stack _top Elementen i stacken lagras som länkade noder. Insättning och borttagning görs i början av kedjan av effektivitetsskäl. Den blir då toppen av stacken. Vi får skapa en Node-klass för noderna där man kan spara ett stackelement och en pil till nästa nod (länk). I Stack-klassen måste man ha en instansvariabel, _top, för att spara minnesreferensen till första noden (toppen på stacken). 9
Nodimplementation av ADT:n Stack public class Stack<E> { private Node<E> _top; public Stack() { _top = null; public boolean isempty() { return _top == null; _top _top newnode public void push(e element) { Node<E> newnode = new Node<E>(element); newnode.setnext(_top); _top = newnode; public E pop() { E top = _top.getelement(); _top = _top.getnext(); return top; { top _top _top... { {...... newnode _top newnode _top...... 10
Lab 5: Nodimplementation av ADT:n Lista Syftet med denna laboration är att - ge övning i att implementera en länkad lista, - ge övning i testning I laboration 4 använde vi listor av typen DefaultList- Model för att lagra personerna. I laboration 5 är det meningen att vi ska göra en egen listklass som bygger på länkade noder. Tanken är att denna nya lista ska ersätta listorna av typen DefaultListModel i lab 4 och att allt ska fungera som tidigare. Eftersom vi vill att den nya listan ska fungera tillsammans med Swing-komponenten JList måste den implementera gränssnittet ListModel (se Java API). 11
Klassdiagram I gränssnittet ListModel finns fyra metoder, dessa metoder måste List-klassen implementera för att fungera tillsammans med Jlist. Två av metoderna finns i den abstrakta klassen AbstractListModel och DefaultListModel ärver denna klass och dessa två metoder därifrån. De andra två metoderna (getelementat och getsize) måste DefaultListModelklassen implementera. Låt den nya List-klassen ärva och implementera på samma sätt som DefaultList- Model-klassen. 12
Gränssnittet ListADT För att göra bytet av listor så smidigt som möjligt är det lämpligt att låta Listklassen implementera följande gränssnitt (som finns på kurshemsidan): public interface ListADT { public void insertelementat(int index, Object anobject); public void addelement(object anobject); public void removeelementat(int index); public boolean removeelement(object anobject); public void removeallelements(); public void sort(); public boolean contains(object anobject); public int indexof(object anobject); public boolean isempty(); public int getsize(); public int size(); public Object getelementat(int index); public Object get(int index); I detta gränssnitt finns förhoppningsvis alla de listmetoder med som använts i laboration 4. Saknas någon lägg till metoden i gränssnittet, men ta inte bort något från gränssnittet. Observera att vissa av metoderna i gränssnittet är "dubletter", de ska göra samma sak men de har olika namn. 13
Den nya listan och JList För att listklassen ska fungera tillsammans med JList måste listans lyssnare underrättas varje gång en ändring görs av listan. Detta gör man med metoder som finns i klassen AbstractListModel. Följande tre metoder är användbara: - void fireintervaladded(object source, int index0, int index1) (AbstractListModel subclasses must call this method after one or more elements are added to the model) - void fireintervalremoved(object source, int index0, int index1) (AbstractListModel subclasses must call this method after one or more elements are removed from the model) - void firecontentschanged(object source, int index0, int index1) (AbstractListModel subclasses must call this method after one or more elements of the list change) Se nodimplementationen av Stack-klassen för ett exempel på hur metoderna används. 14
Alternativ 1: Alternativ 2: List-klass public class Lista extends.. implements.. { private Node<Object> _head; private int _size;... public class Lista extends.. implements.. { private Node _head; private int _size;... _head 15
getnodeat-metoden (en användbar hjälpmetod i list-klassen) Till skillnad från stackimplementationen vill vi med listan kunna besöka noder lite var som helst i kedjan (inte bara i början). Då är följande metod användbar: //pre: 0<= index < size() //post: resultat = nod med index // index i listan private Node getnodeat(int index) { Node n = _head; for (int i = 0; i < index; i++) n = n.getnext(); return n; första varvet index 0 1 2... _head n n......... 16
index i!= 0: Insättning i listan index 0 1 2... i-1 i _head......... 1) Hitta rätt plats för insättning: Node prev = getnode(i-1); 2) Skapa en ny nod och lägg ny data i den: Node newnode = new Node(...); 3) Koppla in den nya noden i listan genom att koppla om pilar: (a) newnode.setnext(prev.getnext()); (b) prev.setnext(newnode);............ prev newnode (a) (b)... 17
Insättning i listan index i = 0: index 0 1 2... _head............ newnode (a) (b)... 1) Skapa en ny nod och lägg ny data i den: Node newnode = new Node(...); 2) Koppla in den nya noden i listan genom att koppla om pilar: (a) newnode.setnext(_head); (b) _head = newnode; Detta ska göras i metoden insertelementat. Hur ska man göra i metoden addelement? Tänk på att använda de metoder som finns. Glöm ej _size! 18
index i!= 0: _head Borttagning ur listan index 0 1 2... i-1 i i+1........................ prev 1) Hitta noden som ligger före den som ska tas bort: Node prev = getnode(i-1); 2) Koppla bort noden genom att koppla om pilar: prev.setnext(prev.getnext().getnext()); 19
Borttagning ur listan index i = 0: index 0 1 2... _head............ 1) Koppla bort noden genom att koppla om pilar: _head = _head.getnext(); Detta ska göras i metoden removeelementat. Hur ska man göra i metoden removeelement? Tänk på att använda de metoder som finns (indexof). Vad ska göras i metoden removeallelements? Glöm ej _size! 20
Sortering Använd någon av sorteringsalgoritmerna - Bubble sort (bubbelsortering) - Insertion sort (instickssortering) tag ett element stick in på rätt plats - Selection sort (urvalssortering) välj ut nästa element och sätt in sist Det finns Objekt-objekt i listan. Hur jämför man dessa? Använd objektens tostring-metoder och använd String-klassens compareto-metod: string1.compareto(string2) = { +1, string1 och string2 ej i alf. ordn. 0, string1 och string2 är lika -1, string1 och string2 i alf. ordn. 21
Övriga metoder i ListADT contains: använd indexof indexof: returnerar -1 om objektet ej i listan, använd equals-metoden när objekt jämförs isempty, size, getsize: uppenbara getelementat, get: använd getnode 22