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