Föreläsning 11 Innehåll Sortering O(n 2 )-algoritmer: urvalsering insättningsering O(n log n)-algoritmer: Merge Quick Heap behandlades i samband med prioritetsköer. Undervisningsmoment: föreläsning 11, övningsuppgifter 12 Sortering Varför era? För att göra sökning effektivare. För att förenkla vissa algoritmer. Varför olika eringsalgoritmer? Olika eringsalgoritmer passar bra i olika sammanhang. Ingen enskild algoritm är bäst i alla möjliga situtioner. Avsnitt i läroboken: 8.1-8.2, 8.4-8.5, 8.7, 8.9 I gamla upplagan: 10.1-10.2, 10.4-10.5, 10.7, 10.9 PFK (Föreläsning 11) HT 2016 1 / 36 PFK (Föreläsning 11) HT 2016 2 / 36 Sortering i Java I klassen java.util.arrays finns metoder för att era vektorer t ex: public static void (int[] items) public static void (Object[] items) elementen jämförs med compareto public static <T> void (T[] items, Comparator<? super T> comp) elementen jämförs med comp.compare Exempel: int[] a = {1, 4, 1, 9, 5, 2, 6; Arrays.(a); I klassen java.util.collections finns metoder för att era listor (t.ex. listor av typen ArrayList och LinkedList). Sortering i Java Comparable Person[] a = new Person[5]; a[0] = new Person("C", "2"); a[1] = new Person("B", "1"); a[2] = new Person("A", "3"); a[3] = new Person("D", "5"); a[4] = new Person("E", "4"); Arrays.(a); Klassen Person måste implementera interfacet Comparable. Inuti metoden används compareto för att jämföra elementen. PFK (Föreläsning 11) HT 2016 3 / 36 PFK (Föreläsning 11) HT 2016 4 / 36
Sortering i Java Comparator Person[] a = new Person[5]; a[0] = new Person("C", "2"); a[1] = new Person("B", "1"); a[2] = new Person("A", "3"); a[3] = new Person("D", "5"); a[4] = new Person("E", "4"); Arrays.(a, new NameComparator()); Klass som implementerar interfacetcomparator: public class NameComparator implements Comparator<Person> { public int compare(person p1, Person p2) { return p1.getname().compareto(p2.getname()); Sortering i Java Lambdauttryck Person[] a = new Person[5]; a[0] = new Person("C", "2"); a[1] = new Person("B", "1"); a[2] = new Person("A", "3"); a[3] = new Person("D", "5"); a[4] = new Person("E", "4"); Arrays.(a, (p1,p2)-> p1.getname().compareto(p2.getname())); Istället för att skriva en klass som implementerar interfacet Comparator kan vi använda ett lambdauttryck. Inuti metoden används compare för att jämföra elementen. Inuti metoden används compare för att jämföra elementen. PFK (Föreläsning 11) HT 2016 5 / 36 PFK (Föreläsning 11) HT 2016 6 / 36 Urvalering i vektor Urvalsering Urvalering (eng. selection ) Sök sta elementet i den oerade delen av vektorn och byt plats med första oerade element ( = första elementet i den oerade delen): Tidsomplexitet: n 1 + n 2 + + 1 = O(n 2 ) Tidskomplexitet är O(n 2 ). Efter k pass är de k sta (eller största) elementen erade. Kan därför vara lämplig om man bara vill få fram de k sta (eller största) och k är litet. Tidskomplexitet är då O(k n) En bättre (effektivare) variant av urvalsering är att använda en prioritetskö: Placera elementen i en prioritetskö (n st. offer). Minsta elementet tas sedan successivt ut (n st. poll). eller Bygg heap och era på plats i vektorn (Heap). Tidskomplexiteten blir i bägge fallen O(n log n). PFK (Föreläsning 11) HT 2016 7 / 36 PFK (Föreläsning 11) HT 2016 8 / 36
Insättningsering i vektor Insättningsering (eng. insertion ) o Element på plats k i vektorn sätts in på rätt plats bland de redan erade elementen på platserna 0..k 1 Detta görs för k = 1, 2,,n o o o Tidskomplexitet (värstafall): 1 + 2 + 3 + + n 1 = n(n 1)/2 = O(n 2 ). Även medelfallet kan visas vara O(n 2 ). o PFK (Föreläsning 11) HT 2016 9 / 36 Insättningsering public static <T extends Comparable<? super T>> void (T[] a) { for (int i = 1; i < a.length; i++) { T nextval = a[i]; int nextpos = i; while (nextpos > 0 && nextval.compareto(a[nextpos - 1]) < 0) { a[nextpos] = a[nextpos - 1]; nextpos--; a[nextpos] = nextval; PFK (Föreläsning 11) HT 2016 10 / 36 Insättningsering Merge Sortera med söndra- och härskateknik Tidskomplexitet är O(n 2 ) ivärstafallochimedelfall. Dock bra metod om vektorn är nästan erad från början: Om vektorn är erad utförs bara en jämförelse per pass tidskomplexiteten blir då O(n). Om vektorn består av n erade element följda av k oerade behövs endast k pass. Man börjar med att era in det (n + 1):a sedan det (n + 2):a o s v. I varje pass görs i värsta fall O(n) jämförelser. Totalt O(k n) d.v.s. O(n) om k är litet i förhållande till n. Sortera vänstra halvan Sortera högra halvan Samera de båda erade halvorna 7 2 5 9 3 8 10 2 2 5 7 9 2 3 8 10 2 2 3 5 7 8 9 10 PFK (Föreläsning 11) HT 2016 11 / 36 PFK (Föreläsning 11) HT 2016 12 / 36
Samering av erade följder algoritm Algoritm Givet två följder v1 och v2 med element erade i växande ordning. Samera till en följd res. Algoritm: i = j = k = 0 så länge det finns obehandlade element kvar i både v1 och v2 jämför elementet i v1[i] med elementet i v2[j] om det sta elementet är från v1 res[k] = v1[i] i = i + 1 annars res[k] = v2[j] j = j + 1 k = k + 1 Samering av erade följder exempel v1 1 4 6 6 v1 1 4 6 6 v1 1 4 6 6 v1 1 4 6 6 v2 2 4 7 v2 2 4 7 v2 2 4 7 v2 2 4 7 res res 1 res 1 2 res 1 2 4 v1 1 4 6 6 v1 1 4 6 6 v1 1 4 6 6 v2 2 4 7 v2 2 4 7 v2 2 4 7 res 1 2 4 4 res 1 2 4 4 6 res 1 2 4 4 6 6 v1 1 4 6 6 En av följderna v1 och v2 har obehandlade element kvar. Flytta dessa element till res. v2 res 2 4 7 1 2 4 4 6 6 7 PFK (Föreläsning 11) HT 2016 13 / 36 PFK (Föreläsning 11) HT 2016 14 / 36 Sameringen i Merge Sameringen i Merge Exempel IsameringsstegetiMerge(merge)motsvarasdebådaföljderna v1 och v2 av de båda erade vektorhalvorna. Det går inte att utföra sameringen i den ursprungliga vektorn. En hjälpvektor, lika stor som den som ska eras, behövs. Slå samman delvektorerna v1 och v2 i vektorn a (bestående av ett element vardera): a 7 2 5 9 3 8 10 2 När man i merge-steget skall slå samman två delvektorer: tmparray 2 7 används motsvarande utrymme i hjälpvektorn (tmparray): Resultatet flyttas sedan tillbaka till den ursprungliga vektorn. Resultatet flyttas sedan tillbaka till ursprungsvektorn. a 2 7 5 9 3 8 10 2 PFK (Föreläsning 11) HT 2016 15 / 36 PFK (Föreläsning 11) HT 2016 16 / 36
merge implementeringsskiss Slå samman de erade delvektorerna a[leftpos].. a[rightpos - 1] och a[rightpos].. a[rightend]: private static <T extends Comparable<? super T>> void merge(t[] a, T[] tmparray, int leftpos, int rightpos, int rightend) { int leftend = rightpos - 1; int tmppos = leftpos; rightend merge implementeringsskiss Forts while (leftpos <= leftend && rightpos <= rightend) { if (a[leftpos].compareto(a[rightpos]) <= 0) { tmparray[tmppos] = a[leftpos]; leftpos++; else { tmparray[tmppos] = a[rightpos]; rightpos++; tmppos++; /* Nu är en av delvektorerna tom. Kopiera över resten av elementen i den icke tomma vektorn till tmparray */ leftpos rightpos /* Flytta till sist tillbaks elementen från tmparray till motsvarande platser i a */ PFK (Föreläsning 11) HT 2016 17 / 36 PFK (Föreläsning 11) HT 2016 18 / 36 Merge implementering Är merge stabil? /** Sorterar elementen i vektora a */ public static <T extends Comparable<? super T>> void (T[] a) { T[] tmparray = (T[]) new Comparable[a.length]; mergesort(a, tmparray, 0, a.length - 1); private static <T extends Comparable<? super T>> void mergesort(t[] a, T[] tmparray, int, int last) { if ( < last) { int mid = ( + last) / 2; mergesort(a, tmparray,, mid); mergesort(a, tmparray, mid + 1, last); merge(a, tmparray,, mid + 1, last); Stabila eringsalgoritmer bibehåller ordningen för element med lika nycklar efter eringen. Exempel: Antag att vi har personer ordnade efter förnamn: Ada Andersson, Bo Eriksson, Lars Andersson, Lena Andersson Om vi vill era efter efternamn istället, men samtidigt bibehålla ordningen mellan förnamnen så måste vi använda en stabil eringsalgoritm. Ada Andersson, Lars Andersson, Lena Andersson, Bo Eriksson Är merge stabil? PFK (Föreläsning 11) HT 2016 19 / 36 PFK (Föreläsning 11) HT 2016 20 / 36
Merge tidskomplexitet Quick Att samera två erade delvektorer av sammanlagd storlek n kostar n. 1 merge av två delvektorer av storlek n/2, kostnad n 2 merge av två delvektorer av storlek n/4, kostnad 2 n/2 = n 4 merge av två delvektorer av storlek n/8, kostnad 4 n/4 = n Söndra- och härskaalgoritm. Sämre än Merge och Heap i värsta fall. Bättre (snabbare) i medelfall. Värstafallet kan göras statistiskt osannolikt. Antal nivåer = log n =) total kostnad n log n PFK (Föreläsning 11) HT 2016 21 / 36 PFK (Föreläsning 11) HT 2016 22 / 36 Quick algoritm Quick implementering Välj ut ett element (element). Se till att det hamnar på rätt plats: Flytta om elementen så att element apple hamnar till vänster och element hamnar till höger. Kallas partitionering av vektorn. x x x Pivot-elementet, på rätt plats Upprepa rekursivt på de båda delvektorerna till vänster respektive till höger om elementet. public static <T extends Comparable<? super T>> void (T[] a) { quicksort(a, 0, a.length - 1); /* Privat hjälpmetod. Sorterar delvektorn a[]..a[last] */ private static <T extends Comparable<? super T>> void quicksort(t[] a, int, int last) { if ( < last) { int pivindex = partition(a,, last); quicksort(a,, pivindex - 1); quicksort(a, pivindex + 1, last); PFK (Föreläsning 11) HT 2016 23 / 36 PFK (Föreläsning 11) HT 2016 24 / 36
Quick val av Quick partitioneringssteget Iprincipkanvilketelementsomhelstväljas. Vi börjar för enkelhets skull med att välja första elementet i vektorn. Inte särskilt bra val. Vi återkommer senare med en diskussion om bättre val. Sök från vänster upp ett element som är. Sök från höger upp ett element som är apple. Byt plats på dessa. Fortsätt tills hela vektorn genomletats. Pivotelementet kan sättas in mellan de båda vektordelarna som uppstår. Arbetet blir proportionellt mot vektorns längd. PFK (Föreläsning 11) HT 2016 25 / 36 PFK (Föreläsning 11) HT 2016 26 / 36 Partitionering exempel = 6 6 1 8 9 4 3 5 2 0 7 Efter byte: 6 1 0 9 4 3 5 2 8 7 Partitionering erad vektor Dåligt val av Om vektorn är erad och om väljs som första elementet hamnar Quick i sitt värsta fall: 6 1 0 9 4 3 5 2 8 7 = 1 1 2 3 4 5 6 7 8 Efter byte: 6 1 0 2 4 3 5 9 8 7 Byt plats på detta och 6 1 0 2 4 3 5 9 8 7 1 2 3 4 5 6 7 8 Byt plats på detta och 5 1 0 2 4 3 6 9 8 7 Tom vektordel till vänster Alla element utom ett till höger Detta upprepas i alla rekursiva upplagor. PFK (Föreläsning 11) HT 2016 27 / 36 PFK (Föreläsning 11) HT 2016 28 / 36
Quick tidskomplexitet Quick bättre val av Man kan visa att det bästa fallet för Quick är när vektorn delas mitt itu i varje rekursiv upplaga. Då är tidskomplexiteten = O(n log n) Välj median av första, mittersta och sista elementet. Elierar riskerna i samband med erad eller nästan erad indata. x 6 1 4 9 8 3 5 2 7 0 x x left mid right Sämsta fall är när den ena delvektorn blir tom i varje rekursiv upplaga. Då är tidskomplexiteten = O(n 2 ) x x Sortera de tre elementen i växande ordning: 0 1 4 9 6 3 5 2 7 8 left mid right Median av de tre är nu mittelementet. PFK (Föreläsning 11) HT 2016 29 / 36 PFK (Föreläsning 11) HT 2016 30 / 36 Quick bättre val av Forts Byt elementet på plats mid med elementet på plats left. Då hamnar elementet längs till vänster precis som förut. 6 1 4 9 0 3 5 2 7 8 Nu kan partitioneringssteget utföras som förut. Varianter av partitioneringssteget Stanna eller ej (och byta) vid likhet med? Om vi inte stannar och byter och alla nycklar är lika hamnar vi i sämsta fallet. 5 5 5 5 5 5 5 5 5 5 Om vi stannar och byter och alla nycklar är lika blir det bästa fallet. 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 Man brukar rekommendera att stanna och byta vid likhet. PFK (Föreläsning 11) HT 2016 31 / 36 PFK (Föreläsning 11) HT 2016 32 / 36
Quick efter partitioneringen Sortering - sammanfattning Efter partitioneringen eras delvektorerna a[low]a[pivindex-1] och a[pivindex+1]a[high] rekursivt. I praktiken låter man av effektivitetsskäl metoden avstanna när delvektorn i det rekursiva anropet är dre än 10-20. Den då nästan färdigerade vektorn kan eras av någon metod som är bra på nästan erad indata. T.ex. är insättningsering lämplig. Urvalsering O(n 2 ) Långsam för stora n. Efter k pass är de k sta erade. Insättningsering O(n 2 ) Bra för nästan erad indata (linjär då). Heaps O(n log n) Kan utformas så att inget extra nesutrymme krävs. I praktiken långsammare än Quick. Efter k pass är de k största elementen erade. Merge O(n log n) Kräver extra nesutrymme. I praktiken långsammare än Quick. Kan utformas iterativt och användas för att era element som finns på fil. Quick O(n log n) Men O(n 2 ) ivärstafall.ingetextranesutrymme för temporär vektor krävs. Bäst av de nämnda i praktiken om man väljer och utför partitionering förnuftigt. PFK (Föreläsning 11) HT 2016 33 / 36 PFK (Föreläsning 11) HT 2016 34 / 36 Sortering Datorlaboration 6 Exempel på vad du ska kunna Redogöra för och jämföra olika eringsalgoritmer: Insättningsering i vektor Urvalsering i vektor Heap (behandlas i samband med prioritetsköer). Merge Quick Genomföra ering på enkla exempel med ovan nämnda metoder Samera två erade följder Förklara begreppen -element och partitionering (Quick). Använda idéerna från eringsalgoritmerna för att lösa andra problem (t.ex. partionering från quick eller sammanslagning av erade följder från merge (se t.ex. övningsuppgifter 13). Använda en map för att implementera en telefonkatalog. Grafiskt användargränssnitt med menyer för att hantera telefonkatalogen. Innehåll: ADT Map, använda klasser från java.util, JavaFX. PFK (Föreläsning 11) HT 2016 35 / 36 PFK (Föreläsning 11) HT 2016 36 / 36