F13 Läsanvisning: kap 8 mer sortering! heapsort! (insertionsort)! (selectionsort) topologisk sortering Nästa gång: gammal tenta Nästa gång är på Tisdag 28/2 som också är sista föreläsningen. (dvs ingen F på fredag 24/2) Sortering 2 1
En liten snabbtitt på några O(n 2 ) metoder Sortering 2 2
Datastrukturer för att utveckla algoritmer Om vi får en osorterad sekvens av tal som vi skall sortera kan vi göra det i 2 steg: 1 sätt in alla talen i en prioritetskö, 2 tag ut alla tal ur kön (i ordning) Om vi nu implementerar p-kön med en osorterad lista så kommer vi i princip att göra selectionsort. 1=O(n), 2=O(n 2 ) (dvs 2 = välj det minsta ur de osorterade) n + n+(n-1)+(n-2)+... + 2+1 = O(n 2 ) Om vi implementerar p-kön med sorterad lista så kommer vi i princip att göra insertion sort. (dvs 1 = lägg in på rätt plats i fältet) 1=O(n 2 ), 2=O(n) 1+2+... +(n-2)+(n-1)+n + n = O(n 2 ) Kan en annan datastruktur göra att denna idé kan utföras snabbare? Sortering 2 3
Heapsort Om vi använder balanserade träd kan bägge dessa operationer göras på O(logn) vilket ger O(nlogn) för hela sorteringen... idén bygger på ett vi skapar en heap av fältet. Då ligger minsta elementet först, vi tar ut det och återställer heapen upprepa... ordna fältet så det är en heap dvs ett POV träd i ett fält (men vi vill inte skapa ett nytt fält!) tag ut det minsta elementet och återställ POV egenskapen upprepa vi tar ut det minsta genom att byta plats på det första (=minsta) elementet och det sista, sedan genom att byta plats på det första och det näst sista osv. Fältet blir sorterat i avtagande ordning. Vill vi ha det i stigande ordning så byter vi bara ordning på heapen dvs lägger största först. Sortering 2 4
En heap Trädet är partiellt ordnat och vänsterbalanserat A(1) innehåller roten. Om barnen existerar så har vi att: Vänster barn till A(i) är i A(2*i). Höger barn till A(i) är i A(2*i+1) Förälder till A(i) är i A(i div 2). Ex: A(4)s barn finns i A(8) och A(9). A(4)s förälder finns i A(2) Sortering 2 5
pushdown Roten (f(first)) antas vara den enda noden som inte uppfyller POV egenskapen i förhållande till sina barn. Metoden pushar ner f(first) till rätt plats så POV egenskapen gäller hela trädet igen. om i=last/2 => i har bara ett barn till vänster: jämför f(i) och f(2*i) och byt eventuellt annars har i två barn, byt med minsta barnet: f(i)>f(vänster barn) och if f(i)>f(2i) f(vänster barn)<=f(höger barn) && f(2i) <=f(2i+1) byt med vänster barn swap(f(i), f(2i)) flytta i i=2i f(i)>f(höger barn) och if f(i)>f(2i+1) f(höger barn)<f(vänster barn) && f(2i+1) < f(2i) byt med höger barn swap(f(i), f(2i+1)) flytta i i=2i+1 Sortering 2 6
pseudocode pushdown(int[] f, first, last ) int i = first; //actual position while i <= last/2 loop if 2*i == last //one child at 2*i if f(i) > f(2*i) then swap( f(i), f(2*i) ); end if exit // exit from loop else //children at 2*i and 2*i+1 if f(i) > f(2*i) && f(2*i) <= f(2*i+1) swap( f(i), f(2*i) ) //to the left i = 2*i; elsif f(i) > f(2*i+1) && f(2*i+1) < f(2*i) swap( f(i), f(2*i+1) ) // to the right i = 2*i+1; else exit; // tree is POV end if end if end loop end pushdown Sortering 2 7
Heapsort Vi får ett osorterat fält. Först måste vi skapa ett POV träd. Vi kan använda pushdown för det också. pushdown(i,j) ordnar f(i) till f(j) i är index för det element vi vill pusha ner i trädet och j är index för det sista elementet i trädet. pseudocode heapsort(array(1..n) f) for i in n/2..1 loop // skapa ett POV-träd pushdown(i,n); end loop for i in n..2 loop // plocka ut minsta, lägg sist swap(f(1), f(i)); // och återställ pov-egenskapen pushdown(1,i-1); end loop end heapsort Sortering 2 8
Allmänt om heapsort Stabilitet: hs är inte stabil, swappar okontrollerat Minne: om den implementeras rekursivt så behöver hs mellan logn och n extra minne för rekursionen Redan sorterat: Ingen förändring. De upprepade deletemin görs fortfarande. Alla lika: Inga pushdown alls behöver rimligen göras och då bör det gå på O(n). Osorterade i slutet: Deletemin dominerar som vanligt men lite färre pushdown. Insprängda: Som ovan. Komplexitet jämförelser: O(nlogn) Komplexitet byten: O(nlogn). Det finns många fler sorteringsmetoder: http://en.wikipedia.org/wiki/sorting_algorithm listar 44st Sortering 2 9
Varför inte alltid quicksort? - kräver minne för rekursionen O(logn)-O(n) - ej stabil - kräver att man hittar bra pivotelement - WC är O(n 2 ) + generellt snabb O(nlogn) Varför inte alltid mergesort? - kräver mycket extra minne O(n) - generellt långsammare än QS + WC är O(nlogn) + stabil Varför inte alltid heapsort? - långsammare trots WC O(nlogn) - ej stabil + minne O(1) Stabil: behåller ordningen på lika element. Spelar inte så stor roll på primitiva typer men är viktigt om man sorterar flera gånger på olika attribut tex först på datum och sedan på avsändare (av mail). Detta garanteras av en stabil metod. Sortering 2 10
O(nlogn) är optimalt Man kan bevisa att det krävs O(nlogn) operationer för att sortera när man jämför tal så våra sorterings-metoder är optimala. Kan man verkligen inte sortera snabbare? Jodå, om man vet mer om det som skall sorteras Olika former av Facksortering (Counting sort, Pigeonhole sort, Bucket sort, Radix sort) Algoritmer där man inte jämför nycklar med varandra utan som bygger på att sortera i fack istället (distribution sort). Objekten måste gå att avbilda på heltalen och man behöver ett fält med storlek Sortering 2 11
Enklaste exemplet: Vi har 1000 tal i intervallet 1..5000. N = största - minsta talet +1 n = antalet tal att sortera dvs N = 5000, n = 1000 int[] input = new int[1000] med tal int[] count = new int[5000] for (i = 0; i < input.length; i++) count[input[i]] += 1 i = 0; for (x = 0; x < count.length; x++) for (y = 0; y < count[x]; y++) { input[i] = x i = i + 1 } fig 1 Komplexiteten O(n+N), Sortering 2 12
Pigeonhole sort: Antag att talen är nyckel: (5, "kalle") (3, "hobbe") (8, "fantomen") (5, "king") Vi behöver ett pigeonhole fält för tal mellan 3 och 8 dvs N = 8-3+1=6 3: (3, "hobbe") 4: 5: (5, "kalle"), (5, "king") 6: 7: 8: (8, "fantomen") Sedan itererar man över fältet och konkatenerar listorna Kan göras stabil. Komplexitet O(n+N) Sortering 2 13
Radix sort, Bucket sort är en generalisering där man sorterar flera varv utifrån olika siffror i talen (eller låter ett fack vara flera tal.) least significant digit (LSD) stabil most significant digit (MSD) ej stabil Antag fält med index 0..9 och en kö i varje Original lista: 170, 45, 75, 90, 802, 2, 24, 66 Sortera på minst signifikanta siffran: 170, 045, 075, 090, 802, 002, 024, 066 170, 090, 802, 002, 024, 045, 075, 066 sedan på nästa siffra (10 tals): 802, 002, 024, 045, 066, 170, 075, 090 sedan på mest signifikanta sifran (100 tals): 002, 024, 045, 066, 075, 090, 170, 802 Kompl.: O(nw) där w är antalet siffror i största talet Minne: extra fält och listor O(f+n) där f=antalet fack Sortering 2 14
java.util.arrays metoder för fält This class contains various methods for manipulating arrays (such as sorting and searching). This class also contains a static factory that allows arrays to be viewed as lists. 18 överlagrade statiska sorteringsmetoder Primitiva typer: static void sort(int[] a) static void sort(int[] a, int fromindex, int toindex) Sorts the specified array of ints into ascending numerical order. The sorting algorithm is a tuned quicksort, adapted from Jon L. Bentley and M. Douglas McIlroy's "Engineering a Sort Function", Software- Practice and Experience, Vol. 23(11) P. 1249-1265 (November 1993). This algorithm offers n*log(n) performance on many data sets that cause other quicksorts to degrade to quadratic performance. Dessutom finns det metoder för byte, char, short, long, double, float Sortering 2 15
java.util.arrays för objekt: static void sort(object[] a)... static void sort(object[] a, int fromindex, int toindex)... Sorts the specified array of objects into ascending order, according to the natural ordering of its elements. All elements in the array must implement the Comparable interface. Furthermore, all elements in the array must be mutually comparable (that is, e1.compareto(e2) must not throw a ClassCastException for any elements e1 and e2 in the array). This sort is guaranteed to be stable: equal elements will not be reordered as a result of the sort. The sorting algorithm is a modified mergesort (in which the merge is omitted if the highest element in the low sublist is less than the lowest element in the high sublist). This algorithm offers guaranteed n*log(n) performance. static <T> void sort(t[] a, Comparator<? super T> c) Övrigt: binarysearch, copyof, copyof Range, fill, equals, hashcode, tostring deepequals, deephashcode, deeptostring Sortering 2 16
java.util.collections med 's' This class consists of static methods that operate on or return collections. The great majority of the algorithms provided operate on List instances, but a few of them operate on arbitrary Collection instances. Sortering Shuffling (alltså blanda) Data Manipulation (reverse, fill, copy, swap, addall, rotate) Sökning (binarysearch) Composition (frequency, disjoint) Extrem Värden (min, max) Sortering 2 17
I Java 7 gick man över till Timsort (för Objekt) som uppfanns 2002 och har wc nlogn och är stabil. I Wikipedia kan man läsa: Timsort is a hybrid sorting algorithm, derived from merge sort and insertion sort, designed to perform well on many kinds of real-world data. It was invented by Tim Peters in 2002 for use in the Python programming language. The algorithm finds subsets of the data that are already ordered, and uses that knowledge to sort the remainder more efficiently. This is done by merging an identified subset, called a run, with existing runs until certain criteria are fulfilled. Timsort has been Python's standard sorting algorithm since version 2.3. It is also used to sort arrays of non-primitive type in Java SE 7,[2] on the Android platform,[3] and in GNU Octave.[4] Sortering 2 18
Sortering I andra sammanhang tex Topologisk sortering i AOV nätverk Stora projekt delas ofta upp i mindre delar som måste utföras i viss ordning. Tex förkunskapskrav på kurser. Dags är en bra modell för detta. Om det finns en båge i->j så kommer i före j i den topologiska ordningen. En DAG i vilken noderna representerar aktiviteter eller uppgifter och bågarna representerar precedens relationer mellan aktiviteterna kallas ett AOV nätverk (Activity On Vertex) Sortering 2 20
Precedens relationer är strikta partiella ordningar Antag att R är en relation. 1) Irreflexiv omm!xrx 2) Antisymmetrisk omm xry & yrx => x=y 3) Transitiv omm xry & yrz => xrz Antag att R är relationen förkunskapskrav till. Tolkning: 1) ingen kurs är förkunskapskrav till sig själv. 2) två kurser x och y är inte förkunskapskrav till varandra 3) Om x är förkunskapskrav till y och y förkunskapskrav till z så måste x vara förkunskapskrav till z. Sortering 2 21
Givet en graf är det framförallt två saker vi vill göra: 1) Undersöka om grafen verkligen är irreflexiv och antisymmetrisk 2) Hitta en linjär ordning på noderna - Att undersöka om grafen är irreflexiv/antisymmetrisk innebär att söka efter cykler (inkl. självloopar). Det kan göras på flera sätt tex med dfs. Om man hittar en bakåtbåge så har man hittat en cykel. - Att hitta en linjär ordning kan också göras på flera sätt tex med topologisk sortering som också baseras på dfs: Gör en dfs och ordna noderna i omvänd slutordning, se nästa sida Sortering 2 22
Algoritm - modifierad dfs Använd bokens dfs eller:! Stacka noden när den först genomsöks.! När det rekursiva anropet återvänder så skriv. dfs(1) -> 531 dfs(2) -> 42-> addera och vänd 24135 eller dfs(2) -> 5342 dfs(1) -> 1 -> addera och vänd 12435 Men det finns en ännu enklare algoritm. Sortering 2 23
Enklare algoritm för topologisk sortering Gå igenom noderna och räkna antalet inbågar för var och en. (dvs en utbåge bokförs som en inbåge hos en annan nod) Sortera denna lista på antal inbågar. Alla noder med noll inbågar har inga förkunskaper och kan skrivas ut. Samtidigt kan deras utbågar tas bort som inbågar hos respektive nod. Finns det noder kvar men ingen med noll inbågar så finns det ingen topologisk sortering dvs vi har hittat en cykel.. Sortering 2 24
Problem 6, tenta 12/3 2010 Algoritmdesign: Topologisk sortering I ett AOV (Activity On Vertex) nätverk ligger aktiviteten på noderna, bågarna representerar bara en relation mellan noderna. En vanlig sådan relation är måste ske före. Exempel på detta kan vara de kurser ni läser på Chalmers eller olika delprojekt på en byggarbetsplats. Dessa nätverk representeras ofta med en så kallad DAG. Beskriv en DAG. En topologisk sortering innebär att man ordnar aktiviteterna i nätverket så att dom sker i en lämplig ordning med avseende på relationen. I fallet med era kurser innebär det att man får en ordning att läsa kurserna så att förkunskapskraven är uppfyllda. Beskriv en algoritm som givet ett nätverk i form av en graf (dvs inte en DAG utan en vanlig graf) konstruerar en topologisk ordning och skriver ut nodernas namn i denna ordning. Jag vill ha idébeskrivning som förklarar hur och varför algoritmen fungerar och detaljerad pseudokod samt komplexiteten. (14p) Sortering 2 25
Lösning Problem 6, 12/3 2010 1) för varje nod beräknar vi antalet inbågar dvs antalet bågar som går in till en nod från någon annan nod. Det gör vi genom att gå igenom efterföljarlistorna för alla noder i grafen, en efterföljare p innebär att vi ökar räknaren för p. Alla noder vars räknare är noll lägger vi in i en mängd. Vilken som av dessa kan man börja med, ingen av dem har ju någon föregångare. 2) Tag alltså en av dessa noder och skriv ut den. Minska samtidigt räknaren på alla dess efterföljare med ett. Det kommer kanske att innebära att det blir nya noder med noll inbågar, dessa lägger vi in i mängden. 3) iterera 2 tills antingen alla noder är utskrivna (=en topologisk sortering) eller tills det inte finns noder med noll inbågar (men samtidigt finns noder kvar) => Då finns det ingen topologisk sortering utan en cykel. Sortering 2 26
0 Given a directed graph G = (V, E) 1 ts = the result i.e. a list with sorted nodes 2 S = list of all nodes with no incoming edges 3 ie = array with number of in-edges 4 fill ie by traversing the follower list 5 search ie for nodes with 0 in-edges, insert in S 6 while S is non-empty do 7 remove a node n from S 8 insert n into ts 9 for each node m with an edge e from n to m do 10 decrease the counter for m in ie 11 if m has no other incoming edges i.e. the counter in ie == 0 then 12 insert m into S } // end for rad 9 } // end while rad 6 13 if (ts.length!= n) 14 output error message ( at least one cycle ) else 15 println( one topologically sorted order: + ts) Komplexitet: O(n+e) (Skall motiveras, se tavlan) Sortering 2 27
För fullstandighetens skull: Allmänt om Insertionsort Stabil: is är stabil om man testar på "<" men inte om man testar på "<=" (det gäller många metoder) Minne: in place dvs IS behöver inget extra minne Redan sorterat: Kommer att gå igenom listan EN gång utan att bubbla några element => O(n). Alla lika: Som ovan. Osorterade i slutet: Förbättring till O(kn) där k är antalet osorterade element i slutet. Insprängda: O(kn) Komplexitet jämförelser: wc: O(n 2 ) Komplexitet byten: O(n 2 ) Sortering 2 28
Allmänt om selectionsort Stabil: är inte stabil, swappar okontrollerbart Minne: in place dvs inget extra minne Redan sorterat: Ingen förändring. Alla lika: Ingen förändring. Osorterade i slutet: Normalt ingen förändring. Antalet swaps är = antalet element i o- ordning vilket ger mycket få swaps. Även i normalfallet har ss optimalt få swaps. Komplexitet jämförelser: wc O(n 2 ) Komplexitet byten: O(n) *** Detta är selectionsorts stora fördel. Speciellt effektivt blir det för redan sorterat, alla lika och osorterade i slutet alltså. Tidskomplexitet för urvals-, insättnings- och bubbel-sortering: Sortering 2 29