Sorteeralgoritmen Sorteren: aanpak 1 Hoe ga je een rij getallen sorteren met PC? Sorteren door selectie (= selection sort): Zoek de kleinste waarde Sorteer de andere waarden Voeg de kleinste waarde vooraan toe Sorteren door selectie kan recursief geïmplementeerd worden Selection sort: implementatie 1 to ssort :list if emptyp :list [output [] ] localmake “smallest reduce “min : list output fput : smallest (ssort remove.once :smallest :list) end Selection sort: implementatie 1 to remove.once : item :list if equalp :item first :list [output butfirst :list] output fput first :list (remove.once :item butfirst :list) end Sorteren door selectie Probleem: je gaat 2 x door de lijst per oproep 1: om kleinste getal te vinden 2: om dit getal te verwijderen uit de lijst. In de recursieve oproep maak je gebruik van de nieuwe lijst. Selection sort: implementatie 2 to ssort :list if emptyp : list [output [] ] output ssort1 (first :list) (butfirst :list) [] end Selection sort: implementatie 2 to ssort1 :min : in :out if emptyp :in [output fput :min ssort :out] if lessthanp :min (first :in) ~ [output ssort1 :min (butfirst :in) (fput first :in out)] output ssort1 (first :in) (butfirst :in) (fput :min : out) end Sorteren door selectie Stel: rij van 100 getallen Aantal nodige vergelijkingen stap 1: 99 stap 2: 98 … Totaal : 4950 Voor rij van n getallen: (n – 1 ) * n / 2 Sorteren door invoegen Algoritme: Neem bvb het eerste getal van de rij Sorteer de overige waarden van de rij Plaats het gekozen getal op de juiste plaats Aantal vergelijkingen voor rij van lengte n: Hangt af van de input data Minimum: n – 1 (gesorteerde rij) Maximum: n * (n – 1) / 2 (omgekeerd gesorteerde rij) Sorteren: aanpak 2 Hoe ga je 100 pagina’s op juiste volgorde steken? Rij van lengte 100: Opsplitsen in 2 groepen van ca. 50 getallen Sorteren via selectie 2 * 1225 = 2450 => Beter! Beter: Niet één keer, maar meerdere keren opsplitsen Partition Sort: algoritme Bepaal een waarde die ca. mediaan is voor rij (= de rij in ca. gelijke helften deelt) Verdeel de input in een “kleine waarde” – en een “grote waarde” – helft Sorteer elk van beide helften Plaats de gesorteerde “kleine waarde” – helft voor de gesorteerde “grote waarde” – helft Partition sort: implementatie 1 to psort :list if (count :list) < 2 [output : list] localmake “split guess.middle.value :list output sentence psort filter [? < :split] :list psort filter [not (? < :split)] :list end to guess.middle.value :list output ((first :list) + (last :list)) / 2 end Partition sort: optimalisatie We willen het aantal vergelijkingen minimaliseren Waarde om rij in 2 groepen te delen (= “splitswaarde” ) is belangrijk Gemiddelde van eerste en laatste getal: [1 3 5 6 4 2] geeft probleem Gemiddelde van alle getallen: [3 2 1000 5 1 4] geeft probleem Niet 2 keer door de input rij gaan Partition sort: implementatie2 to psort :list if emptyp :list [output [] ] if emptyp butfirst :list [output :list] localmake “split ((first :list) + (last :list))/2 output psort1 :split :list [] [] end Partition sort: implementatie 2 to psort1 :split :in :low :high if emptyp :in [output sentence (psort :low) (psort : high)] if lessthanp first :in : split ~ [output psort1 : split (butfirst :in) (fput first :in :low) :high] output psort1 :split (butfirst :in) :low (fput first :in :high) end Partition Sort Stel als invoer: [4 5 6 4] of [4 4 4 4] => Problemen als eerste getal = laatste getal: Voorgaande algoritme niet zeker eindig => keuze van “splitswaarde” aanpassen Lijst overlopen op zoek naar eerste waarde die verschilt => eventueel veel extra vergelijkingen if equalp first :list last :list [ …] Partition sort: aanpassing Rij splitsen in 3 “emmers” (laag, hoog, gelijk) De emmer “gelijk” moet je niet meer verder sorteren if lessthanp first :in :split […] if equaltop first :in :split […] => 2 bewerkingen nodig per vergelijking Partition sort: implementatie 3 to psort :list if emptyp :list [output [] ] if emptyp butfirst :list [output :list] localmake “split ((first :list) + (last :list))/2 if lessthanp first :list :split ~ [output psort1 :split (butfirst :list) (list first :list) [] ] output psort1 :split (butlast :list) (list last :list) [] end Partition sort: aantal vergelijkingen A. In beste geval: 1ste stap: 100 getallen verdelen over 2 emmers => 100 getallen vergelijken met splitswaarde 2de stap: ca. 2 (= voor elke emmer) * (50 getallen verdelen over 2 emmers) => ca. 100 getallen vergelijken met splitswaarde Elke stap: ca. 100 vergelijkingen Totaal: 100 * # keer Partition sort: aantal vergelijkingen # keer is in beste geval = ²log n Totaal = n * ²log n B. In slechtste geval: Aantal nodige vergelijkingen stap 1: 100 stap 2: 99 stap 3: 98 totaal: ca. 5000 Mergesort Algoritme Verdeel de invoer willekeurig in 2 helften van gelijke grootte Sorteer elk van de beide helften afzonderlijk Voeg de 2 helften samen door de waarden te vergelijken Voordeel: We weten zeker dat de beide helften even groot zijn