Några saker till och lite om snabbare sortering 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 DA2001 (Föreläsning 21) Datalogi 1 Hösten 2009 1 / 18
GOTO och lägen PROGRAM test; LABEL 999; { Deklaration av läge }...... GOTO 999; { hoppa till läge 999 }... 999: { ett läge i programmet }... { Städning...} END. DA2001 (Föreläsning 21) Datalogi 1 Hösten 2009 2 / 18
GOTO och lägen (2) 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 ). DA2001 (Föreläsning 21) Datalogi 1 Hösten 2009 3 / 18
GOTO och lägen (3) PROGRAM test; LABEL 999;... PROCEDURE error; BEGIN Writeln( Allvarligt fel i körningen! Starta om programmet ); GOTO 999;... BEGIN... IF fel THEN error;...{fortsätt bearbetningen} 999: END. DA2001 (Föreläsning 21) Datalogi 1 Hösten 2009 4 / 18
CASE 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. DA2001 (Föreläsning 21) Datalogi 1 Hösten 2009 5 / 18
CASE (2) Ex: 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 2009 6 / 18
CASE (3) Ex: Uppräknade typer utskrift TYPE day = (mon, tue, wed, thu, fri, sat, sun); PROCEDURE writeweekday(aday: day); BEGIN 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 ) END DA2001 (Föreläsning 21) Datalogi 1 Hösten 2009 7 / 18
CASE (4) Ex: Uppräknade typer inmatning FUNCTION readweekday: day; VAR aday: Char; BEGIN 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 BEGIN Write( du måste ange en veckodag! ); readweekday := readweekday END END DA2001 (Föreläsning 21) Datalogi 1 Hösten 2009 8 / 18
Snabbare sortering Principer 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 DA2001 (Föreläsning 21) Datalogi 1 Hösten 2009 9 / 18
Quicksort Förklaring av algoritmen 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 2009 10 / 18
Quicksortalgoritmen PROCEDURE quicksort(var v: vector; left, right: index); VAR pivot: Integer; FUNCTION partition(var v: vector; j, k: index): index; BEGIN 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; BEGIN IF left < right THEN BEGIN pivot := partition(v, left, right + 1); quicksort(v, left, pivot - 1); quicksort(v, pivot + 1, right) END DA2001 (Föreläsning 21) Datalogi 1 Hösten 2009 11 / 18
Quicksort, körexempel 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 2009 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 END DA2001 (Föreläsning 21) Datalogi 1 Hösten 2009 13 / 18
Mergesortalgoritmen (2) merge förbered PROCEDURE merge(l1, L2 : listptr; VAR L3 : listptr); VAR e1, e2, first, last: elptr; BEGIN e1 := L1^.first; e2 := L2^.first; IF e1^.key < e2^.key THEN BEGIN first := e1; e1 := e1^.next END ELSE BEGIN first := e2; e2 := e2^.next last := first; DA2001 (Föreläsning 21) Datalogi 1 Hösten 2009 14 / 18
Mergesortalgoritmen (3) merge kör... WHILE (e1 <> NIL) AND (e2 <> NIL) DO BEGIN IF e1^.key < e2^.key THEN BEGIN last^.next := e1; e1 := e1^.next END ELSE BEGIN last^.next := e2; e2 := e2^.next last := last^.next IF e1 = NIL THEN last^.next := e2 ELSE last^.next := e1; L3^.first := first { merge } DA2001 (Föreläsning 21) Datalogi 1 Hösten 2009 15 / 18
Mergesortalgoritmen (4) För att det ska fungera måste vi först dela listan i delar som i sin tur sorteras: PROCEDURE split(l1, L2, L3 : listptr); VAR tmpel : elptr; BEGIN IF NOT empty(l1) THEN BEGIN tmpel := L1^.first; L1^.first := L1^.first^.next; tmpel^.next := L2^.first; L2^.first := tmpel; split(l1, L3, L2) END DA2001 (Föreläsning 21) Datalogi 1 Hösten 2009 16 / 18
Mergesortalgoritmen (5) mergesort mergesort blir då PROCEDURE mergesort(l : listptr); VAR L1, L2 : listptr; BEGIN IF length(l) > 1 THEN BEGIN L1 := createlist; L2 := createlist; split(l, L1, L2); mergesort(l1); mergesort(l2); merge(l1, L2, L); DA2001 (Föreläsning 21) Datalogi 1 Hösten 2009 17 / 18
Några kommentarer Jag har inte varit smart, bara visat metodiken 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 2009 18 / 18