Länkade listor

Länkade strukturer
Antag att vi vill lagra ett antal objekt med någon form av inbördes relation.
Enklaste strukturen är en linjär lista:
a
first
b
c
d
e
f
last
Alla elementen utom första har en föregångare och alla utom det sista har
en efterföljare.
Exempel: Objekt som man vill ha sorterade på någon viss egenskap, olika
former av köer.
(3 maj 2015 – Länkade listor 1 )
Linjär lista i array eller arraylist
0
a
b
2
1
c
3
4
d
5
e
f
last
first
Fördel: Snabb access till element i viss position (index)
Nackdel: Krångligt (”dyrt”) att ta bort eller lägga till element eftersom
element måste flyttas, arrayutrymmet måste omallokeras.
Obs: Gäller även arraylist även om dess API stödjer det
(3 maj 2015 – Länkade listor 2 )
Linjära listor med länkar
Låt varje objekt peka ut sin efterföljare:
a
b
c
d
e
f
last
first
Fördel: Mer dynamiskt. Element kan läggas in och tas bort var som helst
utan att andra element behöver flyttas.
Nackdel: Svårt (”dyrt”) att hitta element i viss position
(3 maj 2015 – Länkade listor 3 )
Klasser för länkade listor
Java har en standardklass (LinkedList) för länkade listor men
vi skall göra en egen.
Varför? Jo, för att illustrera tekniker att hantera dynamiska strukturer.
Dessutom: Bra övningar i rekursivt tänkande!
En lista är antingen
tom (dvs består av 0 element) eller
består av ett element följt av en lista.
(3 maj 2015 – Länkade listor 4 )
Exempel: Klassen List
Klassen List skall
I
hantera länkade listor med heltal i listnoderna,
I
hålla listorna sorterade (underlättar vissa operationer) och
I
se till att varje lista bara innehåller ett givet värde en gång.
Med andra ord: Klassen representerar mängder med heltal
Anmärkning: Trots att listorna bara innehåller heltal är teknikerna och
algoritmerna generella.
(3 maj 2015 – Länkade listor 5 )
Exempel: Klassen List forts
En enkellänkad lista med heltal kan åskådliggöras så här:
3
5
17
.....
De enskilda elementen i listan representeras
som objekt ur klassen Node:
Observera hur klassen Node innehåller ett
objekt ur klassen Node — en rekursiv definition!
42
class Node {
int data;
Node next;
...
}
(3 maj 2015 – Länkade listor 6 )
Exempel: Klassen List forts
För att hålla reda på listan och gör man typiskt en annan klass:
ListNode
List
3
5
17
.....
42
first
last
public class List {
private Node first;
private Node last;
// Optional
(3 maj 2015 – Länkade listor 7 )
Exempel: Klassen List forts
Klassen Node rör bara listans interna organisation.
Vi placerar den som en private inre klass i klassen List:
public class List {
private static class Node {
int data;
Node next;
Varför static?
Node(int d, Node n) {
data = d;
next = n;
}
}
(3 maj 2015 – Länkade listor 8 )
Klassen List: toString
ListNode
List
3
5
17
.....
42
first
last
public String toString() {
return "[" + toString(first) + "]";
}
(3 maj 2015 – Länkade listor 9 )
Klassen List: toString forts
3
5
17
.....
42
private static String toString(Node n) {
if (n==null) {
return "";
} else {
return n.data + toString(n.next);
}
}
(3 maj 2015 – Länkade listor 10 )
Klassen List: insert
3
5
1
17
8
42
53
public void insert(int k) {
first = insert(k, first);
}
’
(3 maj 2015 – Länkade listor 11 )
Klassen List: insert forts
3
1
5
17
8
42
53
private static Node insert(int k, Node n) {
if (n==null || k<n.data) {
return new Node(k, n);
} else if (k>n.data) {
n.next = insert(k, n.next);
}
return n;
}
(3 maj 2015 – Länkade listor 12 )
Klassen List: remove
3
5
17
42
public void remove(int k) {
first = remove(k, first);
}
(3 maj 2015 – Länkade listor 13 )
Klassen List: remove forts
3
5
17
42
private static Node remove(int k, Node n) {
if (n==null || k<n.data)
throw new ListException("remove: No such element in list: " + k);
else if (k==n.data)
return n.next;
else {
n.next = remove(k, n.next);
return n;
}
}
(3 maj 2015 – Länkade listor 14 )
Klassen List: copy
public List copy() {
return new List(copy(first));
}
// Private constructor
private static Node copy(Node n) {
if (n==null)
return null;
else
return new Node(n.data, copy(n.next));
}
(3 maj 2015 – Länkade listor 15 )
Några alternativa representationer
Dubbellänkat:
3
5
17
42
Kan finna både efterföljare och föregångar på O(1) tid
(3 maj 2015 – Länkade listor 16 )
Några alternativa representationer
Cirkulärt:
3
5
17
42
Hittar både första och sista på O(1) tid!
(3 maj 2015 – Länkade listor 17 )
Några alternativa representationer
Dubbellänkat cirkulärt:
3
5
17
42
Enkellänkat ofta enklast och effektivast!
(3 maj 2015 – Länkade listor 18 )