Föreläsning 12 Innehåll Sortering Sortering O(n 2 )-algoritmer: urvalsering insättningsering O(n log n)-algoritmer: Merge Quick 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. Datavetenskap (LTH) Föreläsning 12 HT 2017 1 / 38 Datavetenskap (LTH) Föreläsning 12 HT 2017 2 / 38 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 Sortering i Java Exempel En vektor med Book-objekt ska eras. Klassen Book: public class Book implements Comparable<Book> { private String isbn; private String title; private String author; private int nbrpages; Exempel: int[] a = {1, 4, 1, 9, 5, 2, 6; Arrays.(a); I interfacet java.util.list finns en metod för att era listan (fungerar alltså för t.ex. ArrayList och LinkedList). // konstruktor och övriga metoder public int compareto(book o) { return isbn.compareto(o.isbn); Datavetenskap (LTH) Föreläsning 12 HT 2017 3 / 38 Datavetenskap (LTH) Föreläsning 12 HT 2017 4 / 38
Sortering i Java Comparable Book[] a = new Book[4]; a[0] = new Book("isbn4", "titleb", "authorc", 125); a[1] = new Book("isbn3", "titlea", "authorc", 523); a[2] = new Book("isbn2", "titled", "authora", 199); a[3] = new Book("isbn1", "titlec", "authorb", 278); Arrays.(a); // eras efter isbn-nummer Klassen Book måste implementera interfacet Comparable. Inuti metoden används compareto för att jämföra elementen. Datavetenskap (LTH) Föreläsning 12 HT 2017 5 / 38 Sortering i Java Comparator Book[] a = new Book[4]; a[0] = new Book("isbn4", "titleb", "authorc", 125); a[1] = new Book("isbn3", "titlea", "authorc", 523); a[2] = new Book("isbn2", "titled", "authora", 199); a[3] = new Book("isbn1", "titlec", "authorb", 278); // era efter titlar Arrays.(a, new TitleComparator()); Klass som implementerar interfacet Comparator: public class TitleComparator implements Comparator<Book> { public int compare(book b1, Book b2) { return b1.gettitle().compareto(b2.gettitle()); Inuti metoden används compare för att jämföra elementen. Datavetenskap (LTH) Föreläsning 12 HT 2017 6 / 38 Sortering i Java Lambdauttryck Sortera efter titlar: Arrays.(a, (b1, b2) -> b1.gettitle().compareto(b2.gettitle()) ); Sortera efter antal sidor: Arrays.(a, (b1, b2) -> b1.nbrpages() - b2.nbrpages() ); 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. Kommentar: om subtraktion i Comparator I föregående bild används subtraktion för att få ett värde < 0, == 0, > 0: b1.nbrpages() - b2.nbrpages() Differensen får fel tecken om termerna är väldigt stora (i storleksordningen Integer.MAX_VALUE eller MIN_VALUE), och har olika tecken. Problemet kallas overflow, och har att göra med att datatypen int har ett begränsat maximalt antal siffror (32 bitar, binära siffror). Overflow kan inte inträffa i vårt exempel med böcker och sidantal.(varför?) Om man hanterar stora tal kan hjälpmetoden Integer.compare användas: Arrays.(a, (b1, b2) -> Integer.compare(b1.nbrPages(), b2.nbrpages()) ); Du kan läsa mer om overflow i lösningsförslaget till övningen om lambda-uttryck (se kurssidan, cs.lth.se/edaa01ht/oevningar). Datavetenskap (LTH) Föreläsning 12 HT 2017 7 / 38 Datavetenskap (LTH) Föreläsning 12 HT 2017 8 / 38
Urvalering i vektor Urvalsering Urvalering (eng. selection ) Sök minsta elementet i den oerade delen av vektorn och byt plats med första oerade element (first = första elementet i den oerade delen): Tidskomplexitet är O(n 2 ). first first min first first Efter k pass är de k minsta (eller största) elementen erade. Kan därför vara lämplig om man bara vill få fram de k minsta (eller största) och k är litet. Tidskomplexitet är då O(k n) min min min first min Tidskomplexitet: n 1 + n 2 + + 1 = O(n 2 ) Datavetenskap (LTH) Föreläsning 12 HT 2017 9 / 38 Datavetenskap (LTH) Föreläsning 12 HT 2017 10 / 38 Insättningsering i vektor Diskutera Insättningsering (eng. insertion ) 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 Blir urvalsering snabbare eller långsammare om vektorns element råkar vara erade i stigande ordning? o o o Blir insättningsering snabbare eller långsammare om vektorns element råkar vara erade i stigande ordning? o Tidskomplexitet (värstafall): 1 + 2 + 3 + + n 1 = n(n 1)/2 = O(n 2 ). Även medelfallet kan visas vara O(n 2 ). Datavetenskap (LTH) Föreläsning 12 HT 2017 11 / 38 Datavetenskap (LTH) Föreläsning 12 HT 2017 12 / 38
Insättningsering 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; 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. Datavetenskap (LTH) Föreläsning 12 HT 2017 13 / 38 Datavetenskap (LTH) Föreläsning 12 HT 2017 14 / 38 Merge Sortera med söndra- och härskateknik 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 Merge samering av erade följder Algoritm Givet två följder och med element erade i växande ordning. Samera till en följd. Algoritm: i = j = k = 0 så länge det finns obehandlade element kvar i både och jämför elementet i [i] med elementet i [j] om det minsta elementet är från [k] = [i] i = i + 1 annars [k] = [j] j = j + 1 k = k + 1 En av följderna och har obehandlade element kvar. Flytta dessa element till. Datavetenskap (LTH) Föreläsning 12 HT 2017 15 / 38 Datavetenskap (LTH) Föreläsning 12 HT 2017 16 / 38
Samering av erade följder exempel Sameringen i Merge 1 4 6 6 1 4 6 6 1 4 6 6 1 4 6 6 1 4 6 6 1 1 4 6 6 1 2 1 4 6 6 1 2 4 IsameringsstegetiMerge(merge)motsvarasdebådaföljderna och 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. När man i merge-steget skall slå samman två delvektorer: 1 2 4 4 1 2 4 4 6 1 2 4 4 6 6 används motsvarande utrymme i hjälpvektorn (tmparray): 1 4 6 6 1 2 4 4 6 6 7 Resultatet flyttas sedan tillbaka till ursprungsvektorn. Datavetenskap (LTH) Föreläsning 12 HT 2017 17 / 38 Datavetenskap (LTH) Föreläsning 12 HT 2017 18 / 38 Sameringen i Merge Exempel Slå samman delvektorerna och i vektorn a (bestående av ett element vardera): a tmparray 7 2 5 9 3 8 10 2 2 7 Resultatet flyttas sedan tillbaka till den ursprungliga vektorn. 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 a 2 7 5 9 3 8 10 2 leftpos rightpos Datavetenskap (LTH) Föreläsning 12 HT 2017 19 / 38 Datavetenskap (LTH) Föreläsning 12 HT 2017 20 / 38
merge implementeringsskiss Forts Merge implementering 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 ten av elementen i den icke tomma vektorn till tmparray */ /* Flytta till sist tillbaks elementen från tmparray till motsvarande platser i a */ /** 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 first, int last) { if (first < last) { int mid = first + (last - first) / 2; mergesort(a, tmparray, first, mid); mergesort(a, tmparray, mid + 1, last); merge(a, tmparray, first, mid + 1, last); Datavetenskap (LTH) Föreläsning 12 HT 2017 21 / 38 Datavetenskap (LTH) Föreläsning 12 HT 2017 22 / 38 Stabila eringsalgoritmer Merge tidskomplexitet Stabila eringsalgoritmer Bibehåller ordningen för element med lika nycklar efter eringen. Att samera två erade delvektorer av sammanlagd storlek n kostar n. 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 den tidigare ordningen mellan förnamnen så måste vi använda en stabil eringsalgoritm. Ada Andersson, Lars Andersson, Lena Andersson, Bo Eriksson Är merge stabil? 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 Antal nivåer = log n =) total kostnad n log n Datavetenskap (LTH) Föreläsning 12 HT 2017 23 / 38 Datavetenskap (LTH) Föreläsning 12 HT 2017 24 / 38
Quick Quick algoritm Välj ut ett element (element). Se till att det hamnar på rätt plats: Söndra- och härskaalgoritm. Oftast snabb Sämre än Merge i värsta fall O(n 2 ). Bra (snabb) i medelfall O(n log n). Värstafallet kan göras statistiskt osannolikt. Inget extra minnesutrymme för temporär vektor krävs. 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 pektive till höger om elementet. Datavetenskap (LTH) Föreläsning 12 HT 2017 25 / 38 Datavetenskap (LTH) Föreläsning 12 HT 2017 26 / 38 Quick implementering Quick val av public static <T extends Comparable<? super T>> void (T[] a) { quicksort(a, 0, a.length - 1); /* Privat hjälpmetod. Sorterar delvektorn a[first]..a[last] */ private static <T extends Comparable<? super T>> void quicksort(t[] a, int first, int last) { if (first < last) { int pivindex = partition(a, first, last); quicksort(a, first, pivindex - 1); quicksort(a, pivindex + 1, last); 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. Datavetenskap (LTH) Föreläsning 12 HT 2017 27 / 38 Datavetenskap (LTH) Föreläsning 12 HT 2017 28 / 38
Quick partitioneringssteget Partitionering exempel = 6 6 1 8 9 4 3 5 2 0 7 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. Efter byte: Efter byte: 6 1 0 9 4 3 5 2 8 7 6 1 0 9 4 3 5 2 8 7 6 1 0 2 4 3 5 9 8 7 6 1 0 2 4 3 5 9 8 7 Byt plats på detta och 5 1 0 2 4 3 6 9 8 7 Datavetenskap (LTH) Föreläsning 12 HT 2017 29 / 38 Datavetenskap (LTH) Föreläsning 12 HT 2017 30 / 38 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: = 1 Byt plats på detta och 1 2 3 4 5 6 7 8 1 2 3 4 5 6 7 8 Quick tidskomplexitet 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) x x Sämsta fall är när den ena delvektorn blir tom i varje rekursiv upplaga. Då är tidskomplexiteten = O(n 2 ) x Tom vektordel till vänster Alla element utom ett till höger Detta upprepas i alla rekursiva upplagor. x x Datavetenskap (LTH) Föreläsning 12 HT 2017 31 / 38 Datavetenskap (LTH) Föreläsning 12 HT 2017 32 / 38
Quick bättre val av Välj median av första, mittersta och sista elementet. Eliminerar riskerna i samband med erad eller nästan erad indata. 6 1 4 9 8 3 5 2 7 0 left mid right Sortera de tre elementen i växande ordning: 0 1 4 9 6 3 5 2 7 8 left mid right 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. Median av de tre är nu mittelementet. Datavetenskap (LTH) Föreläsning 12 HT 2017 33 / 38 Datavetenskap (LTH) Föreläsning 12 HT 2017 34 / 38 Varianter av partitioneringssteget Quick efter partitioneringen 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 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 mindre ä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. 5 5 5 5 5 5 5 5 5 5 Man brukar rekommendera att stanna och byta vid likhet. Datavetenskap (LTH) Föreläsning 12 HT 2017 35 / 38 Datavetenskap (LTH) Föreläsning 12 HT 2017 36 / 38
Sortering 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). Datavetenskap (LTH) Föreläsning 12 HT 2017 37 / 38 Datorlaboration 6 Map, hashtabell Implementera en map med en egen öppen hashtabell. 0 1 2 3 4 table.length -1 null null null null key value next key value null next key value next null Tips: Det ska vara en öppen hashtabell. Entry-objekten fungerar även som noder i en enkellänkad lista. Innehåll: abstrakta datatypen map, öppen hashtabell, länkade listor, generisk klass Datavetenskap (LTH) Föreläsning 12 HT 2017 38 / 38