Sorteren van lijsten

advertisement
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
Download