Några saker till och lite om snabbare sortering GOTO och lägen GOTO hemskt eller ett måste? CASE enkla val över diskreta värdemängder Snabb sortering principer Snabb sortering i Scheme och Pascal QuickSort (dela städat slå ihop) Mergesort (dela slå ihop städat) Andra snabbsorteringar översikt PROGRAM test; LABEL 999; { Deklaration av läge } GOTO 999; { hoppa till läge 999 } 999: { ett läge i programmet } { Städning }. DA2001 (Föreläsning 21) Datalogi 1 Hösten 2010 1 / 18 DA2001 (Föreläsning 21) Datalogi 1 Hösten 2010 2 / 18 GOTO och lägen (2) GOTO och lägen (3) GOTO innebär att nästa sats som exekveras är den sats som står efter det läge som man hoppar till. Man får hoppa ut ur block, men aldrig in i block! För att få läsliga program: Hoppa bara framåt i programmet, aldrig bakåt. Pascal har styrstrukturer som klarar alla de fall där man kan tänka sig att hoppa. Det finns egentligen bara ett tillfälle där hopp är motiverat: Då ett så allvarligt fel inträffar i programmet, att man måste avbryta körningen. Man bör då hoppa till en felhanteringsprocedur som ger en felutskrift och sedan avvecklar körningen ( Graceful breakdown ). PROGRAM test; LABEL 999; PROCEDURE error; Writeln( Allvarligt fel i körningen! Starta om programmet ); GOTO 999; IF fel THEN error; {fortsätt bearbetningen} 999:. DA2001 (Föreläsning 21) Datalogi 1 Hösten 2010 3 / 18 DA2001 (Föreläsning 21) Datalogi 1 Hösten 2010 4 / 18
CASE CASE (2) Ex: IF i IN mängd1 THEN s1 ELSE IF i IN mängd2 THEN s2 kan skrivas som CASE i OF lista1: s1; { mängd1 skriven som en diskret uppräkning } lista2: s2; { mängd2 skriven som en diskret uppräkning } där listorna måste vara disjunkta och endast innehålla konstanter av diskret typ. CASE ch OF 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 : val := Ord(ch) - Ord( 0 ); A, B, C, D, E, F : val := Ord(ch) - Ord( A ) + 10; a, b, c, d, e, f : val := Ord(ch) - Ord( a ) + 10; I de flesta Pascalversioner har denna utökats med ett slaskalternativ : ELSE, OTHERS eller OTHERWISE CASE ch OF 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 : val := Ord(ch) - Ord( 0 ); A, B, C, D, E, F : val := Ord(ch) - Ord( A ) + 10; a, b, c, d, e, f : val := Ord(ch) - Ord( a ) + 10; OTHERWISE error DA2001 (Föreläsning 21) Datalogi 1 Hösten 2010 5 / 18 DA2001 (Föreläsning 21) Datalogi 1 Hösten 2010 6 / 18 CASE (3) Ex: Uppräknade typer utskrift CASE (4) Ex: Uppräknade typer inmatning TYPE day = (mon, tue, wed, thu, fri, sat, sun); PROCEDURE writeweekday(aday: day); CASE aday OF mon: Write( måndag ); tue: Write( tisdag ); wed: Write( onsdag ); thu: Write( torsdag ); fri: Write( fredag ); sat: Write( lördag ); sun: Write( söndag ) FUNCTION readweekday: day; VAR aday: Char; ReadLn(aDay); CASE aday OF m, M : readweekday := mon; i, I : readweekday := tue; o, O : readweekday := wed; t, T : readweekday := thu; f, F : readweekday := fri; l, L : readweekday := sat; s, S : readweekday := sun OTHERWISE Write( du måste ange en veckodag! ); readweekday := readweekday DA2001 (Föreläsning 21) Datalogi 1 Hösten 2010 7 / 18 DA2001 (Föreläsning 21) Datalogi 1 Hösten 2010 8 / 18
Snabbare sortering Principer Quicksort Förklaring av algoritmen I de tre långsamma metoderna vi gått igenom byter man i någon mening hela tiden plats på element intill varandra För att sortera snabbare måste man byta plats över längre avstånd Vi har då minst två metoder för att göra dessa byten Grovsortera i mindre och mindre delar tills vi kan slå ihop resultaten Dela utan kontroll och slå ihop med 100% kontroll Vi ska titta på ett exempel för var och en av metoderna Quicksort, som följer den första principen genom 1. Välj en pivot (uttalas pivå ) 2. Flytta allt som är pivot till vänster om pivot och allt som är > pivot till höger om pivot 3. pivot står rätt så gör om på delarna tills allt står rätt Mergesort, som följer den andra genom 1. Dela ner tills man har listor som är 1 element långa 2. Gör parvis merge på delarna tills man har bara en lista 1. Välj en pivot (enklast möjliga strategi = första elemene 2. Sätt en pekare på första elementet och en på sista 3. Flytta förstaelementpekaren till vi hittar ett element som är > pivot 4. Flytta sistaelementpekaren till vi hittar ett element som är pivot 5. byt plats på de funna elementen 6. fortsätt rekursivt med att sortera element pivot och sedan element > pivot Jag tänker mig samma definitioner som tidigare då vi diskuterat sökning Quicksort lämpar sig bäst för stora kontinuerliga listor DA2001 (Föreläsning 21) Datalogi 1 Hösten 2010 9 / 18 DA2001 (Föreläsning 21) Datalogi 1 Hösten 2010 10 / 18 Quicksortalgoritmen Quicksort, körexempel PROCEDURE quicksort(var v: vector; left, right: index); VAR pivot: Integer; FUNCTION partition(var v: vector; j, k: index): index; swap(v, (j + k) DIV 2, j); REPEAT REPEAT j := Succ(j) UNTIL (j > k) OR (v[j] > v[left]); REPEAT k := Pred(k) UNTIL v[k] <= v[left]; IF j < k THEN swap(v, j, k); UNTIL j > k; swap(v, left, k); partition := k; IF left < right THEN pivot := partition(v, left, right + 1); quicksort(v, left, pivot - 1); quicksort(v, pivot + 1, right) 23 17 5 13 9 22 2 15 5 2 (9) 13 23 22 17 15 (2) 5 9 13 23 22 17 15 2 5 9 17 15 13 (22) 23 2 5 9 13 (15) 17 22 23 2 5 9 13 15 17 22 23 DA2001 (Föreläsning 21) Datalogi 1 Hösten 2010 11 / 18 DA2001 (Föreläsning 21) Datalogi 1 Hösten 2010 12 / 18
Mergesortalgoritmen Mergesort lämpar sig bäst för diskontinuerliga listor och filer. Idén är enkel: Om man har redan sorterade listor samsorteras dessa enligt: 1. Jämför första elementen i listorna och tag det minsta av dem tills den ena listan är slut 2. Häng på den lista som inte tog slut TYPE keytype = Integer; elptr = ^element; element = RECORD key : keytype; next : elptr listptr = ^list; list = RECORD first : elptr Mergesortalgoritmen (2) merge förbered PROCEDURE merge(l1, L2 : listptr; VAR L3 : listptr); VAR e1, e2, first, last: elptr; e1 := L1^.first; e2 := L2^.first; IF e1^.key < e2^.key THEN first := e1; e1 := e1^.next ELSE first := e2; e2 := e2^.next last := first; DA2001 (Föreläsning 21) Datalogi 1 Hösten 2010 13 / 18 DA2001 (Föreläsning 21) Datalogi 1 Hösten 2010 14 / 18 Mergesortalgoritmen (3) merge kör... Mergesortalgoritmen (4) För att det ska fungera måste vi först dela listan i delar som i sin tur sorteras: WHILE (e1 <> NIL) AND (e2 <> NIL) DO IF e1^.key < e2^.key THEN last^.next := e1; e1 := e1^.next ELSE last^.next := e2; e2 := e2^.next last := last^.next IF e1 = NIL THEN last^.next := e2 ELSE last^.next := e1; L3^.first := first { merge } PROCEDURE split(l1, L2, L3 : listptr); VAR tmpel : elptr; IF NOT empty(l1) THEN tmpel := L1^.first; L1^.first := L1^.first^.next; tmpel^.next := L2^.first; L2^.first := tmpel; split(l1, L3, L2) DA2001 (Föreläsning 21) Datalogi 1 Hösten 2010 15 / 18 DA2001 (Föreläsning 21) Datalogi 1 Hösten 2010 16 / 18
Mergesortalgoritmen (5) mergesort mergesort blir då Några kommentarer Jag har inte varit smart, bara visat metodiken PROCEDURE mergesort(l : listptr); VAR L1, L2 : listptr; IF length(l) > 1 THEN L1 := createlist; L2 := createlist; split(l, L1, L2); mergesort(l1); mergesort(l2); merge(l1, L2, L); Man kan effektivisera mergesort genom att bara hantera elementpekare. Man kan effektivisera quicksort genom en enkel stack och avveckla rekursionen Mergesort är alltid snäll, quicksort kan spåra ur (men det är ovanligt) Man kan använda långsamma metoder på korta listor, och bara använda de tyngre men snabbare på långa listor. Det finns flera metoder, en rolig (men ganska obegriplig) är heapsort som alltid är snäll och n log n quicksort < mergesort < heapsort <... < utbytessortering http://linux.wku.edu/~lamonml/algor/ DA2001 (Föreläsning 21) Datalogi 1 Hösten 2010 17 / 18 DA2001 (Föreläsning 21) Datalogi 1 Hösten 2010 18 / 18