Prioritetskö, heap, heapsort, datarepresentationer

TDDC30
Objektorienterad programmering i Java, datastrukturer och algoritmer. Föreläsning 9
Jonas Lindgren, Institutionen för Datavetenskap, LiU
På denna föreläsning:
•
Prioritetskö
•
Heap
•
Representation som länkat träd, array
•
Heapsort
1
Innan vi börjar:
• Glöm inte att anmäla er till tentan via
studentportalen!
• Det finns två tentapass, det spelar ingen roll
vilket man anmäler sig till. Men man får bara gå
upp på ett av dem i denna tentaperiod.
• Träd-quiz!
• https://www.mentimeter.com/s/7f6d7f3331dd70c41c2fa46d243a4026/0c0de7a350ba
2
Problemet?
• Scenario 1: I ett musikspelarprogram kan användaren lägga till
låtar i en spellista. Programmet spelar sedan upp låtarna i
prioritetsordning. Prioriteten bygger på betyg, hur ofta en låt
har spelats, och hur länge sedan den senast spelades upp.
• Scenario 2: Ett flygbolag har ett fullbokat plan. Fler kunder vill
följa med så de ställer sig på en standby-kö. Vilka som får ta
ev. avbokade platser beror betalad summa, frequent flyer
poäng, etc..
3
ADT Prioritetskö
Definition
• En prioritetskö är en samling nyckel-värde par med två
fundamentala metoder:
insert(prioritet, värde)
Associerar ett värde med en nyckel
värde removeMin()
Tar bort och returnerar elementet med högst
prioritet
• Nyckeln kan vara vilken typ som helst: tal, bokstäver, datum ...
• Nyckeln anger värdets prioritet.
• (mindre värde på prioritet => ”högre” prioritet)
4
ADT Prioritetskö – variant 1
Gränssnittet för ADT prioritetskö:
insert(nyckel, värde)
Associerar ett värde med en nyckel
värde removeMin()
Tar bort och returnerar elementet med högst
prioritet
värde min()
Returnerar elementet med högst prioritet
int size()
Returnerar antalet element i kön
boolean isEmpty()
Testar om kön är tom
• Stoppas in i godtycklig ordning
• Tas ut i sorterad ordning
5
ADT Prioritetskö - variant 2
(PriorityQueue i Java)
• Prioritetskön tar bara värdena vid insättning. Prioriteten tar man reda
på genom att jämföra värdena med varandra:
• A) Man skickar med en komparator (ett ”jämföringsobjekt”) när man
anropar P-köns konstruktor.
• B) Man låter värdena vara jämförbara genom att låta klassen
implementera interfacet Comparable.
PriorityQueue<Song> pQ
= new PriorityQueue<Song>(
new SongComparator() );
PriorityQueue<Song> pQ
= new PriorityQueue<Song>();
class Song implements Comparable {6
…
}
Jämförbara objekt
För att vi ska kunna använda objekt som nycklar:
• Måste de implementera interfacet Comparable:
public class Song implements Comparable<Song> {
…
int compareTo(Song right) { … }
}
P-kön anropar
compareTo på sina
element. D.v.s vår
compareTo-metod,
via polymorfi!
• Eller ha en motsvarande Comparator:
public class SongComparator implements Comparator<Song> {
…
int compare(Song left, Song right) { … }
boolean equals(Song left, Song right) { … }
}
7
Sortering
Det går att sortera med hjälp av en prioritetskö!
PriorityQueue<Song> pq = new PriorityQueue<Song>();
// eller pq = new PriorityQueue<Song>(new SongComparator());
for (Song i : unsortedList) {
pq.add(i);
}
while (!pq.isEmpty()) {
sortedList.add(pq.removeMin());
}
8
Implementation
• Implementation som en osorterad lista..
• Blir som selection sort när vi väljer!
H
(6, ’A’)
(4, ’X’)
(8, ’E’)
(2, ’Y’)
/
(8, ’E’)
/
• Implementation som en sorterad lista..
• Blir som insertion sort när vi stoppar in!
H
(2, ’Y’)
• Komplexitet?
(4, ’X’)
(6, ’A’)
Metod
Osorterad lista Sorterad lista
size, isEmpty
O(1)
O(1)
insert
O(1)
O(n)
min, removeMin
O(n)
O(1)
9
Implementation (2)
Metod
Osorterad lista Sorterad lista
size, isEmpty
O(1)
O(1)
insert
O(1)
O(n)
min, removeMin
O(n)
O(1)
• Alltså:
• om det är många insättningsoperationer jmf med remove => välj
osorterad lista som implementation.
• om det är många remove-operationer jmf med insert (?) => välj
sorterad lista som implementation.
Om min algoritm gör ungefär lika
många remove som insert, blir det ju
ändå O(n)…
Kan man inte få så att båda
operationerna går halvsnabbt?
10
Självklart!
Heap
• En heap är ett fullständigt binärt träd
• höjd = log(n)
• Inte ett binärt sökträd, men..
• För varje nod har dess förälder lika eller mindre nyckel
• Kallas även för min-heap. (Tvärt om blir max-heap).
• Den minsta nyckeln finns alltid i roten
2
3
7
8
5
9
11
Insättning i Heap
1. Lägg in den nya noden sist i heapen
2. Låt noden ”bubbla uppåt” tills totalordningen återställts
2
1
3
7
3
8
5
9
1
7
2
5
9
8
12
Borttagning ur heap
1. Ta bort rotnoden och ersätt den med noden i slutet av
trädet
2. Låt den nya roten bubbla nedåt i trädet tills totalordningen
återställts
• Bubbla alltid med rotens minsta barn
2
9
3
7
3
8
5
9
7
3
5
8
5
7
8
9
13
Arrayrepresentation
• En heap representeras med fördel med ett fält
• Kompakt!
ADT
Representation
2
2 3 8 7 5 9
3
7
8
5
9
Index för root
0
Index för vänster barn
2*i+1
Index för höger barn
2*i+2
Index för förälder
(i-1)/2 (avrunda nedåt)
14
Komplexitet
Operation
Tid
size, isEmpty
O(1)
min
O(1)
insert
O(log(n))
removeMin
O(log(n))
• Att skapa en heap med n element med hjälp av insert tar O(nlog(n)) tid
• Det finns bättre sätt!
15
Skapa en heap
Algoritm för att heapordna en godtycklig array:
1. Börja med att se löven som separata heapar innehållandes
en nod var
2. Koppla successivt ihop löven, via sina föräldrar.
• Bubbla vid behov ned föräldranoden till korrekt plats
3. Upprepa för varje nivå, nedifrån och upp
Komplexitet...
Räkna antalet bubblingar i värstafallet
T(n) = n/2 + n/4 + n/8 + ... <= n
O(n)
16
Heapsort
Algoritm
1. Skapa en heap (O(n))
• Måste sorteras i ”omvänd” ordning!
2. Utför removeMin för varje element och spara i ett fält
• O(nlog(n))
• Spegelvänder heapens ordning
• Kan utföras in-place!
• Fältet konverteras till en heap
• Elementen plockas bort ur heapen och stoppas in i fältet, från
höger till vänster
Komplexitet: O(n) + O(nlog(n)) = O(nlog(n))
17