Heapsort: verschil tussen versies
Verwijderde inhoud Toegevoegde inhoud
Geen bewerkingssamenvatting |
k Fix interwiki conflict, we zijn overgeschakeld op Wikidata |
||
Regel 1:
'''Heapsort''' is een snel [[sorteeralgoritme]], ontwikkeld in 1964 door [[Robert W. Floyd]] en J. W. J. Williams. Het probeert, net zoals [[straight selection sort]], het grootste element van de te sorteren rij te zoeken, dit achteraan te plaatsen en zo met een minder verder te gaan tot alles op volgorde staat. Het algoritme is bijzonder efficiënt in geheugengebruik, maar is niet [[stabiliteit (sorteeralgoritme)|stabiel]].
== Sortering vanuit een heap ==
{{
Het idee achter sortering door middel van heapsort is eigenlijk heel eenvoudig:
# Begin met een rij van te sorteren elementen.
# Definieer een lege rij om de elementen in gesorteerde volgorde op te slaan
# Vorm uit de te sorteren elementen een max-heap; hierin bevindt het element met de grootste waarde zich in de wortel van de [[grafentheorie|boom]].
# Plaats dit element achterin de resultaatrij, op de achterste plaats die nog vrij is. Haal het element uit de rij van te sorteren elementen.
# Als de rij van te sorteren elementen nog niet leeg is, ga dan naar stap 3.
Regel 15:
== Het maken van een heap ==
Zoals te lezen valt in het artikel [[heap]], is het niet nodig om je in allerlei bochten te wringen om een heap te maken – een heap is dan in principe wel een boomstructuur, maar hij kan daarom toch prima opgeslagen worden in een rij (zoals een [[array]]). Als je je maar aan de heap-regel houdt.
Regel 23 ⟶ 22:
<code>
|
</code>
Regel 38 ⟶ 37:
<code>
|
</code>
Dit is bijna goed. Het enige dat niet klopt is dat we met de berekening van links en rechts wel eens waarden kunnen vinden die niet meer in de rij A liggen (die heeft namelijk een eindige grootte lengte.A):
<code>
|
;
;
</code>
Regel 83 ⟶ 82:
<code>
|
</code>
Regel 95 ⟶ 94:
<code>
|
fi
;
fi
;
|
</code>
== Een kleine optimalisatie ==
Het bovenstaande is correct, maar het maakt wel onnodig gebruik van een extra rij B. In iedere slag van het algoritme wordt namelijk precies een element definitief gesorteerd en valt dus weg uit A – dat betekent dat A altijd precies evenveel ruimte open heeft staan als er gesorteerde elementen zijn. Dus kunnen we de gesorteerde rij net zo goed meteen in A opslaan.
Regel 137 ⟶ 135:
<code>
|
fi
;
fi
;
|
</code>
== Efficiëntie ==
Heapsort is een vrij efficiënt algoritme, zowel qua ruimtegebruik als qua [[complexiteitsgraad|orde van looptijd]].
Regel 182 ⟶ 179:
== Een programmavoorbeeld ==
Een implementatie in C:
<code>
}
}
</code>
== Alternatief -- iteratief ==
=== Sortering door middel van heaps ===
De sorteermethode van heapsort is gebaseerd op een oplossing van:
# Maak uit elementen in willekeurige volgorde een rij van die elementen
# Produceer uit die rij van elementen deze elementen in de voorgeschreven volgorde
onder de voorwaarde:
element in
elementen in de rij.
gegeven:
de voorgeschreven volgorde 'geordend.(A,B)' is een [[totale ordening]] en kan tussen willekeurige
elementen in vaste tijd worden geëvalueerd
De oplossing die hier gepresenteerd wordt is een rij met elementen die voldoen aan:
<math>Heap.A=\langle\forall i,j : 2 \times i=j \vee 2 \times i+1=j : geordend.(A.i,A.j) \rangle </math>
of equivalent
<math>Heap.A=\langle\forall i,j : i=j \mathbf{div}2 : geordend.(A.i,A.j) \rangle </math>
=== Het maken van een Heap uit elementen in willekeurige volgorde ===
Men voege een nieuw element toe aan het eind van de rij die de heap bevat en confronteert het met het
element dat het in strijd met de voorwaarde zou kunnen brengen: A.(i DIV 2) , waar i zijn huidige positie is.
Als de heapvoorwaarde niet voldaan is verwisselen we de elementen. Dit wordt herhaald waarbij in elke slag
de index minstens halveert tot het nieuwe element de heapvoorwaarde niet meer verstoort.
Dit moet gebeuren omdat er geen lagere elementen meer zijn of het element index 0 krijgt.
Daar 0 DIV 2 = 0 en een totale ordening o.a. reflexief is geldt geordend(A.0,A.0).
Als we het onderste element van de heap altijd index 0 geven vereenvoudigt dit het programma:
<code>
{ vereist : Heap.A[0:n)
{ vereist : A.lengte
HeapIn ( var A : rij(elem), var n : integer, in : elem, geordend : (elem,elem)->Boolean)
]|
</code>
NB. Heap.A[0:0) is triviaal geldig dus kan een Heap elementsgewijze met
HeapIn vanuit een lege Heap gemaakt worden.
=== Het produceren van elementen uit een Heap in de voorgeschreven volgorde ===
Het te leveren element is A.0.
Vervolgens moet de heap hersteld worden zodanig dat er een nieuwe A.0 is en de heap nu
aan het eind een element korter is.
Dit gebeurt door A.0 te vullen met A.1 en vervolgens de nieuwe vrije plek A.i te vullen met
het element uit {A.(2*i),A.(2*i+1)} dat het eerst voor promotie naar een lagere index in aanmerking komt.
We herhalen dit tot A(2*i+1) niet meer bestaat, waarbij de index van de vrije plek per slag minstens verdubbelt.
Regel 269 ⟶ 261:
<code>
{ vereist : Heap.A[0:n)
{ vereist : A.lengte >= n > 0 }
HeapUit (var A : rij(elem), var n : integer, var uit : elem, geordend : (elem,elem)->Boolean)
]|
</code>
=== Toepassingen ===
Een groot voordeel van dit mechanisme is dat (bijna) de helft van het sorteren geschiedt
tijdens de invoerfase en de rest tijdens de uitvoerfase, en daarmee eventueel kan worden overlapt.
Dat bovendien de werkruimte-overhead O(1) (onafhankelijk van n) is, maakt de methode
aantrekkelijk voor het sorteren van hoeveelheden gegevens die de capaciteit van het snelle
random-access geheugen benadert of overstijgt.
Als dat laatste het geval is kunnen met de routine van een externe ongeordende rij maximaal
lange geordende externe subrijen worden geproduceerd, die vervolgens met behoud van ordening tot
langere subrijen worden samengevoegd tot de beschikbare geheugenruimte voldoende is om alle
resterende subrijen efficiënt tot de gewenste rij (op het externe medium) te combineren.
Ook is het een effectieve 'prioriteits-wachtrij' : als de activiteit met de hoogste prioriteit
de vroegste plaats in de ordening krijgt kan deze in log.n tijd geselecteerd worden. Een nieuwe
activiteit met willekeurige prioriteit kan in log.n tijd in de wachtrij worden gezet (waar n het
aantal wachtende activiteiten is).
=== In-situ sorteren ===
Als een tabel met elementen in snel geheugen reeds bestaat en deze gesorteerd moet worden,
dat wil zeggen er is een in-situsorteerprocedure gewenst, kan dit gerealiseerd worden:
# Transformeer de Tabel van 0 tot Tabel.lengte in een heap doch met omgekeerde van de gewenste volgorde.
# Plaats de uit de heap geproduceerde elementen in de aan het eind vrijkomende plaatsen.
indien een oplopende ordening gewenst is:
<code>
HeapSort (var A : rij(elem))
]|
]|
</code>
Het eerste deel van de slotconditie is geen kunst, het tweede was de opdracht.
Regel 343 ⟶ 334:
<code>
{
{
{
{
}
}
}
[[Categorie:Sorteeralgoritme]]
|