Några saker till och lite om snabbare sortering Generellt om avbrott Generera avbrott Snabb sortering principer Snabb sortering i Scheme och Python QuickSort (dela städat slå ihop) Mergesort (dela slå ihop städat) Andra snabbsorteringar översikt DA2001 (Föreläsning 18) Datalogi 1 Hösten 2013 1 / 16
Lite generellt om avbrottshantering Vi har använt avbrottshantering i våra program men inte talat så mycket om vad man kan / måste / inte får / inte bör göra. En sak är klar, en felmöjlighet som vi inte hanterar i vårt program kan orsaka att vårt program kraschar. På en kurs är det inte farligt men i ett kommersiellt program kan det vara fatalt. Kanske har man en massa filer öppna och kraschen gör att alla filer förblir öppna eller stängs utan att de blivit färdigskrivna. Vi kan alltså förlora data eller introducera fel i skrivna data. Det vi hittills gjort är testa indata (+ lite annat): while True: try: inp = input("mata in ett heltal: ") x = int(inp) break except ValueError: print("hoppsan! ", inp, " är inte ett heltal.", "Försök igen...", sep= )... DA2001 (Föreläsning 18) Datalogi 1 Hösten 2013 2 / 16
Generellt om avbrott Man kan ha flera typer av avbrott för ett kodavsnitt while True: try: inp = input("mata in ett heltal: ") x = int(inp) break except ValueError: print("hoppsan! ", inp, " är inte ett heltal.", "Försök igen...", sep= ) except EOFError: print("inmatningen stängdes av, kan inte kommunicera") break except: print("okänt fel, avbryter") break... DA2001 (Föreläsning 18) Datalogi 1 Hösten 2013 3 / 16
Generellt om avbrott... Bäst är det om man tar hand om alla fel som kan uppstå i en viss situation. Men, om det inte går kan man skicka ett fel vidare till en utanförliggande omgivning while True: try: inp = input("mata in ett heltal: ") x = int(inp) break except ValueError: print("hoppsan! ", inp, " är inte ett heltal.", "Försök igen...", sep= ) except: print("okänt fel, avbryter") raise... Här skickar vi vidare det sista avbrottet så det kan hanteras på en yttre nivå. Bäst är naturligtvis att också ha en felhantering på den yttre nivån DA2001 (Föreläsning 18) Datalogi 1 Hösten 2013 4 / 16
Generellt om avbrott... Det sista exemplet kanske är vanligast vid hantering av filer: import sys try: f = open( myfile.txt ) s = f.readline() i = int(s.strip()) except IOError as err: print("in/ut-matningsfel:", err) except ValueError: print("kunde inte konvertera till ett heltal") except Exception as ex: print("oväntat fel:", ex) raise Fortfarande är det bäst att hantera det vidareskickade felet DA2001 (Föreläsning 18) Datalogi 1 Hösten 2013 5 / 16
Generera avbrott Man kan, om man vill själv generera avbrott och på så sätt få egna texter (svenska?) utskrivna try: f = open( myfile.txt ) s = f.readline() i = int(s.strip()) except IOError as err: print("in/ut-matningsfel:", err) except ValueError: print("kunde inte konvertera till ett heltal") except: raise Exception("Oväntat, okänt fel") Fångas upp på en yttre nivå med: except Exception as e: print("ojdå!", e) DA2001 (Föreläsning 18) Datalogi 1 Hösten 2013 6 / 16
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 18) Datalogi 1 Hösten 2013 7 / 16
Quicksort Förklaring av algoritmen 1. Välj en pivot (enklast möjliga strategi = första elementet, annan strategi = mittersta elementet av tre slumpmässigt valda element eller välj mittersta elementet) 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 DA2001 (Föreläsning 18) Datalogi 1 Hösten 2013 8 / 16
Quicksortalgoritmen def qs(lst, left, right): if right - left > 1: mid = (left + right + 1) // 2 lst[left], lst[mid] = lst[mid], lst[left] pivot = lst[left] le = left + 1 ri = right while le <= ri: while le <= right and lst[le] < pivot: le += 1 while ri > left and lst[ri] >= pivot: ri -= 1 if le < ri: lst[le], lst[ri] = lst[ri], lst[le] lst[ri], lst[left] = lst[left], lst[ri] qs(lst, left, ri-1) qs(lst, ri+1, right) DA2001 (Föreläsning 18) Datalogi 1 Hösten 2013 9 / 16
Quicksort, körexempel lst = [23, 17, 5, 13, 9, 22, 2, 15] qs(lst, 0, len(lst) - 1) ger: 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 18) Datalogi 1 Hösten 2013 10 / 16
Quicksort i Scheme (define (quicksort order) (define (partition alist p q r) (if (null? alist) (list q r) (if (order (car alist) p) (partition (cdr alist) p (cons (car alist) q) r) (partition (cdr alist) p q (cons (car alist) r))))) (define (sort s) (cond ((null? s) ()) ((null? (cdr s)) s) (else (let ((p (partition (cdr s) (car s) () ()))) (append (sort (car p)) (cons (car s) (sort (cadr p)))))))) sort) (define qs (quicksort <)) DA2001 (Föreläsning 18) Datalogi 1 Hösten 2013 11 / 16
Mergesortalgoritmen Mergesort lämpar sig bäst för stora 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 def merge(left, right): result = [] while len(left) > 0 and len(right) > 0: if left[0] <= right[0]: result.append(left.pop(0)) else: result.append(right.pop(0)) if len(left) > 0: result += left else: result += right return result DA2001 (Föreläsning 18) Datalogi 1 Hösten 2013 12 / 16
Mergesortalgoritmen (2) def mergesort(lst): if len(lst) > 1: mid = len(lst) // 2 left = mergesort(lst[:mid]) right = mergesort(lst[mid:]) return merge(left, right) return lst DA2001 (Föreläsning 18) Datalogi 1 Hösten 2013 13 / 16
Mergesortalgoritmen (3), körning [23, 17, 5, 13, 9, 22, 2, 15] ms(3), left = [23] ms(3), right = [17] ms(3), left = [5] ms(3), right = [13] ms(2), left = [17, 23] ms(2), right = [5, 13] ms(3), left = [9] ms(3), right = [22] ms(3), left = [2] ms(3), right = [15] ms(2), left = [9, 22] ms(2), right = [2, 15] ms(1), left = [5, 13, 17, 23] ms(1), right = [2, 9, 15, 22] [2, 5, 9, 13, 15, 17, 22, 23] DA2001 (Föreläsning 18) Datalogi 1 Hösten 2013 14 / 16
Mergesort i Scheme (define (ms order) (define (split alist a b) (if (null? alist) (list a b) (split (cdr alist) b (cons (car alist) a)))) (define (merge a b) (cond ((null? a) b) ((null? b) a) ((order (car a) (car b)) (cons (car a) (merge (cdr a) b))) (else (cons (car b) (merge a (cdr b)))))) (define (sort p) (cond ((null? p) ()) ((null? (cdr p)) p) (else (let ((s (split p () ()))) (merge (sort (car s)) (sort (cadr s))))))) sort) (define msint (ms <)) DA2001 (Föreläsning 18) Datalogi 1 Hösten 2013 15 / 16
Några kommentarer Jag har inte varit smart, bara visat metodiken Man kan effektivisera mergesort genom att bara hantera index, och alltså inte bygga nya listor utan sortera på plats. Man kan effektivisera mergesort genom att ha en extra lista som är lika lång som den man ska sortera och flytta element mellan listorna 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 Python använder en adaptive mergesort, där adaptive betyder att man, beroende på datas egenskaper, väljer en längd under vilken man sorterar med en långsam metod medan längre listor körs med en ganska standard mergesort. quicksort < mergesort < heapsort <... < utbytessortering http://www.daniweb.com/software-development/python/code/216689 DA2001 (Föreläsning 18) Datalogi 1 Hösten 2013 16 / 16